import { test, expect } from "./helpers/fixtures.js"; test.describe("Admin members page", () => { test("members list loads for admin", async ({ adminPage }) => { await adminPage.goto("/admin/members"); await expect(adminPage.locator("h1")).toHaveText("Members"); await expect( adminPage.getByText("Manage members, contributions, and access"), ).toBeVisible(); }); test("search bar works", async ({ adminPage }) => { await adminPage.goto("/admin/members"); const searchInput = adminPage.getByPlaceholder("Search members..."); await expect(searchInput).toBeVisible({ timeout: 10000 }); // Wait for the initial member list to load before searching await expect( adminPage .locator("table") .or(adminPage.getByText("No members found matching your criteria")), ).toBeVisible({ timeout: 15000 }); await searchInput.fill("nonexistent-query-xyz"); // Page should not crash -- either shows filtered results or the empty state await expect( adminPage .locator("table") .or(adminPage.getByText("No members found matching your criteria")), ).toBeVisible({ timeout: 10000 }); }); test("non-admin redirect", async ({ browser }) => { const context = await browser.newContext(); const page = await context.newPage(); await page.goto("/admin/members"); // Admin middleware redirects non-admin users to / or /members await page.waitForURL((url) => !url.pathname.startsWith("/admin")); expect(page.url()).not.toContain("/admin/members"); await context.close(); }); test("add member button opens modal", async ({ adminPage }) => { await adminPage.goto("/admin/members"); await adminPage.waitForLoadState("networkidle"); // ensure Vue hydration is complete // Wait for page to fully load and hydrate await expect(adminPage.locator("h1")).toHaveText("Members"); await adminPage.waitForLoadState("networkidle"); const addBtn = adminPage.getByRole("button", { name: "Add Member" }); await expect(addBtn).toBeVisible({ timeout: 10000 }); await addBtn.click(); // Modal should appear with the form heading and fields await expect(adminPage.getByPlaceholder("Full name")).toBeVisible({ timeout: 10000, }); await expect( adminPage.getByPlaceholder("email@example.com"), ).toBeVisible(); }); test("create member, status select reflects STATUS_LABELS, change persists, detail page renders", async ({ adminPage }) => { const stamp = Date.now(); const memberName = `E2E Member ${stamp}`; const memberEmail = `e2e-member-${stamp}@example.test`; await adminPage.goto("/admin/members"); await adminPage.waitForLoadState("networkidle"); await expect(adminPage.locator("h1")).toHaveText("Members"); await adminPage.getByRole("button", { name: "Add Member" }).click(); await adminPage.getByPlaceholder("Full name").fill(memberName); await adminPage.getByPlaceholder("email@example.com").fill(memberEmail); await adminPage.getByRole("button", { name: "Create Member" }).click(); // Verify the new member shows up via search const searchInput = adminPage.getByPlaceholder("Search members..."); await expect(searchInput).toBeVisible({ timeout: 10000 }); await searchInput.fill(memberEmail); const memberRow = adminPage.locator("tr", { hasText: memberEmail }); await expect(memberRow).toBeVisible({ timeout: 10000 }); await expect(memberRow.getByText(memberName)).toBeVisible(); // Open the edit modal for this member, where the STATUS_LABELS-driven