first implementation
This commit is contained in:
parent
79458bcba4
commit
870804e7b9
24 changed files with 5485 additions and 184 deletions
|
|
@ -1,39 +1,75 @@
|
|||
import { test, expect, Page } from "@playwright/test";
|
||||
import { test, expect, Page, APIRequestContext } from "@playwright/test";
|
||||
|
||||
const API_BASE = "http://localhost:8000";
|
||||
const ADMIN_EMAIL = "admin@example.com";
|
||||
const ADMIN_PASSWORD = "admin123";
|
||||
|
||||
// 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<string> {
|
||||
// Helper to create an invite via API
|
||||
async function createInvite(request: APIRequestContext): Promise<string> {
|
||||
const loginResp = await request.post(`${API_BASE}/api/auth/login`, {
|
||||
data: { email: ADMIN_EMAIL, password: ADMIN_PASSWORD },
|
||||
});
|
||||
const cookies = loginResp.headers()["set-cookie"];
|
||||
|
||||
const meResp = await request.get(`${API_BASE}/api/auth/me`, {
|
||||
headers: { Cookie: cookies },
|
||||
});
|
||||
const admin = await meResp.json();
|
||||
|
||||
const inviteResp = await request.post(`${API_BASE}/api/admin/invites`, {
|
||||
data: { godfather_id: admin.id },
|
||||
headers: { Cookie: cookies },
|
||||
});
|
||||
const invite = await inviteResp.json();
|
||||
return invite.identifier;
|
||||
}
|
||||
|
||||
// Helper to authenticate a user with invite-based signup
|
||||
async function authenticate(page: Page, request: APIRequestContext): Promise<string> {
|
||||
const email = uniqueEmail();
|
||||
const inviteCode = await createInvite(request);
|
||||
|
||||
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");
|
||||
|
||||
// Enter invite code first
|
||||
await page.fill('input#inviteCode', inviteCode);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Wait for registration form
|
||||
await expect(page.locator("h1")).toHaveText("Create account");
|
||||
|
||||
// Fill registration
|
||||
await page.fill('input#email', email);
|
||||
await page.fill('input#password', "password123");
|
||||
await page.fill('input#confirmPassword', "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);
|
||||
test("displays counter value", async ({ page, request }) => {
|
||||
await authenticate(page, request);
|
||||
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);
|
||||
test("displays current count label", async ({ page, request }) => {
|
||||
await authenticate(page, request);
|
||||
await expect(page.getByText("Current Count")).toBeVisible();
|
||||
});
|
||||
|
||||
test("clicking increment button increases counter", async ({ page }) => {
|
||||
await authenticate(page);
|
||||
test("clicking increment button increases counter", async ({ page, request }) => {
|
||||
await authenticate(page, request);
|
||||
await expect(page.locator("h1")).not.toHaveText("...");
|
||||
|
||||
const before = await page.locator("h1").textContent();
|
||||
|
|
@ -41,8 +77,8 @@ test.describe("Counter - Authenticated", () => {
|
|||
await expect(page.locator("h1")).toHaveText(String(Number(before) + 1));
|
||||
});
|
||||
|
||||
test("clicking increment multiple times", async ({ page }) => {
|
||||
await authenticate(page);
|
||||
test("clicking increment multiple times", async ({ page, request }) => {
|
||||
await authenticate(page, request);
|
||||
await expect(page.locator("h1")).not.toHaveText("...");
|
||||
|
||||
const before = Number(await page.locator("h1").textContent());
|
||||
|
|
@ -64,8 +100,8 @@ test.describe("Counter - Authenticated", () => {
|
|||
expect(final).toBeGreaterThanOrEqual(before + 3);
|
||||
});
|
||||
|
||||
test("counter persists after page reload", async ({ page }) => {
|
||||
await authenticate(page);
|
||||
test("counter persists after page reload", async ({ page, request }) => {
|
||||
await authenticate(page, request);
|
||||
await expect(page.locator("h1")).not.toHaveText("...");
|
||||
|
||||
const before = await page.locator("h1").textContent();
|
||||
|
|
@ -77,9 +113,9 @@ test.describe("Counter - Authenticated", () => {
|
|||
await expect(page.locator("h1")).toHaveText(expected);
|
||||
});
|
||||
|
||||
test("counter is shared between users", async ({ page, browser }) => {
|
||||
test("counter is shared between users", async ({ page, browser, request }) => {
|
||||
// First user increments
|
||||
await authenticate(page);
|
||||
await authenticate(page, request);
|
||||
await expect(page.locator("h1")).not.toHaveText("...");
|
||||
|
||||
const initialValue = Number(await page.locator("h1").textContent());
|
||||
|
|
@ -92,7 +128,7 @@ test.describe("Counter - Authenticated", () => {
|
|||
|
||||
// Second user in new context sees the current value
|
||||
const page2 = await browser.newPage();
|
||||
await authenticate(page2);
|
||||
await authenticate(page2, request);
|
||||
await expect(page2.locator("h1")).not.toHaveText("...");
|
||||
const page2InitialValue = Number(await page2.locator("h1").textContent());
|
||||
// The value should be at least what user 1 saw (might be higher due to parallel tests)
|
||||
|
|
@ -130,14 +166,19 @@ test.describe("Counter - Unauthenticated", () => {
|
|||
});
|
||||
|
||||
test.describe("Counter - Session Integration", () => {
|
||||
test("can access counter after login", async ({ page }) => {
|
||||
test("can access counter after login", async ({ page, request }) => {
|
||||
const email = uniqueEmail();
|
||||
const inviteCode = await createInvite(request);
|
||||
|
||||
// Sign up first
|
||||
// Sign up with invite
|
||||
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.fill('input#inviteCode', inviteCode);
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page.locator("h1")).toHaveText("Create account");
|
||||
|
||||
await page.fill('input#email', email);
|
||||
await page.fill('input#password', "password123");
|
||||
await page.fill('input#confirmPassword', "password123");
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page).toHaveURL("/");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue