import { expect, test } from "@playwright/test"; test.describe("Thread detail page", () => { test("loads with candidates visible", async ({ page }) => { await page.goto("/collection?tab=planning"); await page.waitForLoadState("networkidle"); // Click the "New Backpack" thread card await page.getByText("New Backpack").click(); await page.waitForLoadState("networkidle"); // Thread detail page should show the thread name await expect( page.getByRole("heading", { name: "New Backpack" }), ).toBeVisible({ timeout: 5000 }); // Candidates should be visible await expect(page.getByText("ULA Circuit")).toBeVisible({ timeout: 5000 }); await expect(page.getByText("Gossamer Gear Mariposa")).toBeVisible({ timeout: 5000, }); await expect(page.getByText("Granite Gear Crown2 38")).toBeVisible({ timeout: 5000, }); }); test("rank badges are visible for top 3 candidates", async ({ page }) => { await page.goto("/collection?tab=planning"); await page.waitForLoadState("networkidle"); await page.getByText("New Backpack").click(); await page.waitForLoadState("networkidle"); // Rank badges are medal icons — the component renders LucideIcon with name="medal" // for ranks 1, 2, 3. We can verify via SVG elements or by checking the page has // the expected number of medal icons (one per top candidate). // The list view is default, which renders CandidateListItem with RankBadge. // With 3 candidates all in top 3, all 3 get medal icons. await expect(page.locator("text=ULA Circuit")).toBeVisible({ timeout: 5000, }); await expect(page.locator("text=Gossamer Gear Mariposa")).toBeVisible({ timeout: 5000, }); await expect(page.locator("text=Granite Gear Crown2 38")).toBeVisible({ timeout: 5000, }); // Verify candidates are rendered (rank badges are SVG medals, not text) // Check that at least the 3 candidates are present in the list const candidateRows = page.locator(".bg-white.rounded-xl.border"); await expect(candidateRows).toHaveCount(3, { timeout: 5000 }); }); test("comparison view toggle works", async ({ page }) => { await page.goto("/collection?tab=planning"); await page.waitForLoadState("networkidle"); await page.getByText("New Backpack").click(); await page.waitForLoadState("networkidle"); await expect(page.getByText("ULA Circuit")).toBeVisible({ timeout: 5000 }); // The compare button is a button with title="Compare view" (icon button with columns-3 icon) const compareButton = page.getByRole("button", { name: "Compare view" }); await expect(compareButton).toBeVisible({ timeout: 5000 }); await compareButton.click(); // After clicking, a table should appear with Weight and Price row labels await expect(page.locator("table")).toBeVisible({ timeout: 5000 }); // The comparison table renders row labels in sticky cells (exact match to avoid // matching candidate notes that contain the word "weight" or "price") await expect( page.getByRole("cell", { name: "Weight", exact: true }), ).toBeVisible({ timeout: 5000 }); await expect( page.getByRole("cell", { name: "Price", exact: true }), ).toBeVisible({ timeout: 5000 }); // All 3 candidates should appear as table column headers (in ) await expect(page.locator("thead").getByText("ULA Circuit")).toBeVisible({ timeout: 5000, }); await expect( page.locator("thead").getByText("Gossamer Gear Mariposa"), ).toBeVisible({ timeout: 5000 }); }); test("resolved thread shows winner banner", async ({ page }) => { await page.goto("/collection?tab=planning"); await page.waitForLoadState("networkidle"); // Click the "Resolved" tab pill button in the planning view await page.getByRole("button", { name: "Resolved" }).click(); await page.waitForLoadState("networkidle"); // Camp Stove resolved thread should appear await expect(page.getByText("Camp Stove")).toBeVisible({ timeout: 5000 }); // Click the Camp Stove thread card and wait for URL to change to thread detail await page.getByText("Camp Stove").click(); await page.waitForURL(/\/threads\/\d+/, { timeout: 5000 }); await page.waitForLoadState("networkidle"); // Should show the resolved thread heading await expect(page.getByRole("heading", { name: "Camp Stove" })).toBeVisible( { timeout: 5000 }, ); // The winner candidate (BRS-3000T) should be visible in the candidate list await expect(page.getByText("BRS-3000T")).toBeVisible({ timeout: 5000 }); }); });