/** * Base Playwright fixture that combines auth + DB helpers. * * Extends the default `test` object so every test file can * import from here and get typed access to fixtures. * * Usage: * import { test, expect } from '../fixtures/base.fixture'; * test('my test', async ({ authedPage, apiContext }) => { ... }); */ import { test as base, type Page, type APIRequestContext } from '@playwright/test'; import { apiLogin, apiSwitchOrg, authHeaders, type AuthTokens } from './auth.fixture'; import { testDb } from './db.fixture'; import { TEST_USERS } from './test-data'; const API_BASE = process.env.API_BASE_URL || 'http://localhost/api'; type TestFixtures = { /** Pre-authenticated API request context with Bearer token */ authedRequest: APIRequestContext & { _tokens: AuthTokens }; /** Access token string for manual header construction */ accessToken: string; }; type WorkerFixtures = { /** Shared database connection (one per worker) */ db: typeof testDb; }; export const test = base.extend({ /** * Worker-scoped database connection. * Connects once per worker, disconnects when the worker exits. */ db: [ async ({}, use) => { await testDb.connect(); await use(testDb); await testDb.disconnect(); }, { scope: 'worker' }, ], /** * Per-test authenticated API request context. * Logs in as the default test user and attaches the Bearer token. */ authedRequest: async ({ playwright }, use) => { const requestContext = await playwright.request.newContext({ baseURL: API_BASE, }); const tokens = await apiLogin(requestContext, TEST_USERS.treasurer); // If user belongs to orgs, switch to the first one let finalTokens = tokens; if (tokens.organizations?.length > 0) { const orgId = (tokens.organizations[0] as any).id; try { finalTokens = await apiSwitchOrg(requestContext, tokens.accessToken, orgId); } catch { // switch-org may not be needed if token already scoped finalTokens = tokens; } } // Create a new context with the auth header baked in const authedContext = await playwright.request.newContext({ baseURL: API_BASE, extraHTTPHeaders: authHeaders(finalTokens.accessToken), }); // Attach tokens for tests that need them (authedContext as any)._tokens = finalTokens; await use(authedContext as any); await authedContext.dispose(); await requestContext.dispose(); }, accessToken: async ({ authedRequest }, use) => { await use((authedRequest as any)._tokens.accessToken); }, }); export { expect } from '@playwright/test';