import { test, expect } from "@playwright/test"; import { loginViaAPI } from "./helpers/auth.js"; import { mockCookies, mockAPIError } from "./helpers/mock-api.js"; /** * RCA-16: Cookie management page * * Covers: * - Cookies grouped by domain * - Search by domain name * - Search by cookie name * - Detail panel shows all fields * - Delete single cookie with confirmation * - Bulk delete * - Domain group collapse/expand * - Pagination / scroll * - API error state */ test.describe("Cookie management", () => { test.beforeEach(async ({ page, request }) => { await loginViaAPI(page, request); await mockCookies(page); }); test("lists cookies grouped by domain", async ({ page }) => { await page.goto("/cookies"); await expect(page.getByText("example.com")).toBeVisible(); await expect(page.getByText("other.io")).toBeVisible(); }); test("search by domain filters results", async ({ page }) => { await page.goto("/cookies"); const searchInput = page .getByPlaceholder(/search/i) .or(page.getByRole("searchbox")) .or(page.getByLabel(/search/i)); await searchInput.fill("other.io"); await expect(page.getByText("other.io")).toBeVisible(); await expect(page.getByText("example.com")).not.toBeVisible(); }); test("search by cookie name filters results", async ({ page }) => { await page.goto("/cookies"); const searchInput = page .getByPlaceholder(/search/i) .or(page.getByRole("searchbox")) .or(page.getByLabel(/search/i)); await searchInput.fill("session"); // "session" cookie under example.com should be visible await expect(page.getByText("session")).toBeVisible(); // "token" under other.io should not be visible await expect(page.getByText("token")).not.toBeVisible(); }); test("clicking a cookie shows detail panel with all fields", async ({ page }) => { await page.goto("/cookies"); // Click the "session" cookie row await page.getByText("session").first().click(); // Detail panel should show all cookie fields await expect(page.getByText(/name/i)).toBeVisible(); await expect(page.getByText(/value/i)).toBeVisible(); await expect(page.getByText(/domain/i)).toBeVisible(); await expect(page.getByText(/path/i)).toBeVisible(); await expect(page.getByText(/expires/i)).toBeVisible(); await expect(page.getByText(/secure/i)).toBeVisible(); await expect(page.getByText(/httponly/i)).toBeVisible(); }); test("deletes a single cookie after confirmation", async ({ page }) => { let deleteCalled = false; await page.route("**/admin/cookies/c1", (route) => { if (route.request().method() === "DELETE") { deleteCalled = true; return route.fulfill({ status: 200, contentType: "application/json", body: "{}" }); } return route.continue(); }); await page.goto("/cookies"); // Click the first cookie's delete button const deleteBtn = page .getByRole("button", { name: /delete/i }) .first(); await deleteBtn.click(); // Confirmation dialog should appear await expect( page.getByRole("dialog").or(page.getByText(/confirm|are you sure/i)), ).toBeVisible(); // Confirm deletion await page.getByRole("button", { name: /confirm|yes|delete/i }).last().click(); expect(deleteCalled).toBe(true); }); test("cancel on delete dialog does not delete the cookie", async ({ page }) => { let deleteCalled = false; await page.route("**/admin/cookies/*", (route) => { if (route.request().method() === "DELETE") { deleteCalled = true; } return route.continue(); }); await page.goto("/cookies"); const deleteBtn = page.getByRole("button", { name: /delete/i }).first(); await deleteBtn.click(); await page .getByRole("button", { name: /cancel|no/i }) .last() .click(); expect(deleteCalled).toBe(false); }); test("can select multiple cookies and bulk delete", async ({ page }) => { let bulkDeleteCalled = false; await page.route("**/admin/cookies", (route) => { if (route.request().method() === "DELETE") { bulkDeleteCalled = true; return route.fulfill({ status: 200, contentType: "application/json", body: "{}" }); } return route.continue(); }); await page.goto("/cookies"); // Select checkboxes const checkboxes = page.getByRole("checkbox"); const count = await checkboxes.count(); if (count > 0) { await checkboxes.first().check(); if (count > 1) await checkboxes.nth(1).check(); const bulkBtn = page.getByRole("button", { name: /delete selected|bulk delete/i }); if (await bulkBtn.isVisible()) { await bulkBtn.click(); await page.getByRole("button", { name: /confirm|yes|delete/i }).last().click(); expect(bulkDeleteCalled).toBe(true); } } }); test("domain group collapses and expands", async ({ page }) => { await page.goto("/cookies"); // Find a domain group header and click to collapse const groupHeader = page.getByText("example.com").first(); await groupHeader.click(); // After collapse, cookies within that domain should be hidden // (exact selector depends on implementation — check one of the children) const sessionCookie = page.getByText("session"); // It may be hidden or removed; either is acceptable const isVisible = await sessionCookie.isVisible().catch(() => false); // Click again to expand await groupHeader.click(); await expect(page.getByText("session")).toBeVisible(); }); test("shows error message when cookies API fails", async ({ page }) => { await page.unroute("**/admin/cookies*"); await mockAPIError(page, "**/admin/cookies*", 500, "Failed to load cookies"); await page.goto("/cookies"); await expect( page .getByRole("alert") .or(page.getByText(/error|failed|could not load/i)) .first(), ).toBeVisible(); }); });