import { test, expect, Page } from "@playwright/test"; // Helper to generate unique email for each test function uniqueEmail(): string { return `counter-${Date.now()}-${Math.random().toString(36).substring(7)}@example.com`; } // Helper to authenticate a user async function authenticate(page: Page): Promise { const email = uniqueEmail(); await page.context().clearCookies(); await page.goto("/signup"); await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', "password123"); await page.locator('input[type="password"]').nth(1).fill("password123"); await page.click('button[type="submit"]'); await expect(page).toHaveURL("/"); return email; } test.describe("Counter - Authenticated", () => { test("displays counter value", async ({ page }) => { await authenticate(page); await expect(page.locator("h1")).toBeVisible(); // Counter should be a number (not loading state) const text = await page.locator("h1").textContent(); expect(text).toMatch(/^\d+$/); }); test("displays current count label", async ({ page }) => { await authenticate(page); await expect(page.getByText("Current Count")).toBeVisible(); }); test("clicking increment button increases counter", async ({ page }) => { await authenticate(page); await expect(page.locator("h1")).not.toHaveText("..."); const before = await page.locator("h1").textContent(); await page.click("text=Increment"); await expect(page.locator("h1")).toHaveText(String(Number(before) + 1)); }); test("clicking increment multiple times", async ({ page }) => { await authenticate(page); await expect(page.locator("h1")).not.toHaveText("..."); const before = Number(await page.locator("h1").textContent()); await page.click("text=Increment"); await page.click("text=Increment"); await page.click("text=Increment"); await expect(page.locator("h1")).toHaveText(String(before + 3)); }); test("counter persists after page reload", async ({ page }) => { await authenticate(page); await expect(page.locator("h1")).not.toHaveText("..."); const before = await page.locator("h1").textContent(); await page.click("text=Increment"); const expected = String(Number(before) + 1); await expect(page.locator("h1")).toHaveText(expected); await page.reload(); await expect(page.locator("h1")).toHaveText(expected); }); test("counter is shared between users", async ({ page, browser }) => { // First user increments await authenticate(page); await expect(page.locator("h1")).not.toHaveText("..."); const initialValue = Number(await page.locator("h1").textContent()); await page.click("text=Increment"); await page.click("text=Increment"); const afterFirst = initialValue + 2; await expect(page.locator("h1")).toHaveText(String(afterFirst)); // Second user in new context sees the same value const page2 = await browser.newPage(); await authenticate(page2); await expect(page2.locator("h1")).toHaveText(String(afterFirst)); // Second user increments await page2.click("text=Increment"); await expect(page2.locator("h1")).toHaveText(String(afterFirst + 1)); // First user reloads and sees the increment await page.reload(); await expect(page.locator("h1")).toHaveText(String(afterFirst + 1)); await page2.close(); }); }); test.describe("Counter - Unauthenticated", () => { test("redirects to login when accessing counter without auth", async ({ page }) => { await page.context().clearCookies(); await page.goto("/"); await expect(page).toHaveURL("/login"); }); test("shows login form when redirected", async ({ page }) => { await page.context().clearCookies(); await page.goto("/"); await expect(page.locator("h1")).toHaveText("Welcome back"); }); }); test.describe("Counter - Session Integration", () => { test("can access counter after login", async ({ page }) => { const email = uniqueEmail(); // Sign up first await page.goto("/signup"); await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', "password123"); await page.locator('input[type="password"]').nth(1).fill("password123"); await page.click('button[type="submit"]'); await expect(page).toHaveURL("/"); // Logout await page.click("text=Sign out"); await expect(page).toHaveURL("/login"); // Login again await page.fill('input[type="email"]', email); await page.fill('input[type="password"]', "password123"); await page.click('button[type="submit"]'); await expect(page).toHaveURL("/"); // Counter should be visible await expect(page.locator("h1")).toBeVisible(); const text = await page.locator("h1").textContent(); expect(text).toMatch(/^\d+$/); }); test("counter API requires authentication", async ({ page }) => { // Try to access counter API directly without auth const response = await page.request.get("http://localhost:8000/api/counter"); expect(response.status()).toBe(401); }); test("counter increment API requires authentication", async ({ page }) => { const response = await page.request.post("http://localhost:8000/api/counter/increment"); expect(response.status()).toBe(401); }); });