import { test, expect } from "@playwright/test"; import { BASE, requireAuth, injectAuth } from "./helpers"; test.describe("Chat", () => { test("conversations endpoint returns list", async ({ page }) => { const auth = requireAuth(); const res = await page.request.get(`${BASE}/api/chats/conversations`, { headers: { Authorization: `Bearer ${auth.accessToken}` }, }); expect(res.status()).toBe(200); const data = await res.json(); expect(data).toHaveProperty("conversations"); expect(Array.isArray(data.conversations)).toBe(true); }); test("student→student chat is rejected (IDOR guard)", async ({ page }) => { const auth = requireAuth(); const adminId = auth.user!.id; // Create a student const u1 = await page.request.post(`${BASE}/api/admin/users`, { headers: { Authorization: `Bearer ${auth.accessToken}` }, data: { name: "ChatTest", email: "chat-idor@e2e.test", username: "chat_idor_e2e", password: "TestPass123!", role: "student", securityQuestion: "Q", securityAnswer: "A", }, }); // 201 = created, 409 = already exists from prior run — both are fine if (u1.status() !== 201 && u1.status() !== 409) { test.skip(true, `Unexpected status creating test user: ${u1.status()}`); return; } const studentId = u1.status() === 201 ? (await u1.json()).user.id : null; if (!studentId) { test.skip(true, "Could not get student ID"); return; } // Log in as the student const captchaRes = await page.request.get(`${BASE}/api/auth/captcha`); const { challengeId, answer } = await captchaRes.json(); if (!answer) { test.skip(true, "CAPTCHA not solvable"); return; } const loginRes = await page.request.post(`${BASE}/api/auth/login`, { data: { username: "chat_idor_e2e", password: "TestPass123!", challengeId, captchaAnswer: answer }, }); const studentSession = await loginRes.json(); if (!studentSession.accessToken) { test.skip(true, "Student login failed"); return; } // Student tries to read another student's conversations — must fail const forbidden = await page.request.get(`${BASE}/api/chats/${studentId}/messages`, { headers: { Authorization: `Bearer ${studentSession.accessToken}` }, }); expect([403, 404]).toContain(forbidden.status()); }); test("chat page renders without redirect to /login", async ({ page }) => { await injectAuth(page); await page.goto("/unwrap?tab=chats"); await page.waitForLoadState("networkidle", { timeout: 15_000 }); expect(page.url()).not.toContain("/login"); }); });