import { test, expect } from "@playwright/test"; import { resolveUrl, getSessionCookie, parseSSEStream, lastSSEOfType } from "./helpers"; /** * E2E tests for comparison list and detail views. * Covers: /api/comparisons/[slug], /api/user/comparisons */ test.describe("Comparisons", () => { let cookie: string; let testSlug: string; test.beforeAll(async ({ page }) => { cookie = await getSessionCookie(page); // Create a comparison to ensure we have data const res = await page.request.post(resolveUrl("/api/compare"), { data: { query: "Cats vs Dogs", items: ["Cats", "Dogs"] }, headers: { "Content-Type": "application/json", Cookie: cookie, Accept: "text/event-stream" }, timeout: 120_000, }); if (res.ok()) { const body = Buffer.from((await res.body()) ?? []).toString("utf-8"); const events = await parseSSEStream(body); const done = lastSSEOfType(events, "done") as Record | undefined; if (done) { testSlug = (done.done as Record).slug as string; } } }); test("1. User comparisons list returns 200 for authenticated user", async ({ page }) => { const res = await page.request.get(resolveUrl("/api/user/comparisons"), { headers: { Cookie: cookie }, }); expect(res.status()).toBe(200); const data = await res.json(); expect(Array.isArray(data)).toBe(true); }); test("2. User comparisons list requires auth", async ({ page }) => { const res = await page.request.get(resolveUrl("/api/user/comparisons")); expect(res.status()).toBe(401); }); test("3. Get comparison by slug returns 200 with data", async ({ page }) => { if (!testSlug) { test.skip(); return; } const res = await page.request.get(resolveUrl(`/api/comparisons/${testSlug}`), { headers: { Cookie: cookie }, }); expect(res.status()).toBe(200); const data = await res.json(); expect(data).toHaveProperty("slug", testSlug); expect(data).toHaveProperty("status"); expect(["completed", "failed", "researching"]).toContain(data.status); }); test("4. Get comparison by non-existent slug returns 404", async ({ page }) => { const res = await page.request.get(resolveUrl("/api/comparisons/this-slug-does-not-exist-xyz123"), { headers: { Cookie: cookie }, }); expect(res.status()).toBe(404); }); test("5. Comparison slug increments view count", async ({ page }) => { if (!testSlug) { test.skip(); return; } const res1 = await page.request.get(resolveUrl(`/api/comparisons/${testSlug}`), { headers: { Cookie: cookie }, }); const viewsBefore = (await res1.json()).viewCount ?? 0; const res2 = await page.request.get(resolveUrl(`/api/comparisons/${testSlug}`), { headers: { Cookie: cookie }, }); const viewsAfter = (await res2.json()).viewCount ?? 0; expect(viewsAfter).toBeGreaterThanOrEqual(viewsBefore); }); test("6. Comparison response includes all required fields", async ({ page }) => { if (!testSlug) { test.skip(); return; } const res = await page.request.get(resolveUrl(`/api/comparisons/${testSlug}`), { headers: { Cookie: cookie }, }); const data = await res.json(); expect(data).toHaveProperty("id"); expect(data).toHaveProperty("title"); expect(data).toHaveProperty("slug"); expect(data).toHaveProperty("status"); expect(data).toHaveProperty("query"); }); });