Files
pargar/frontend/e2e/chat.spec.ts
T

66 lines
2.6 KiB
TypeScript

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");
});
});