import path from 'node:path'; import { test, expect } from '../fixtures'; /** * NextAuth (browser-session) write gates — `session.user.hasWriteAccess` * checks in viewer-frontend route handlers (see * `app/api/faces/[id]/identify/route.ts`). Distinct from the FastAPI * role-permission gates in `api.role-permissions.spec.ts` (separate user * store, bearer auth instead of session cookies). * * Requires `E2E_VIEWER_EMAIL`/`PASSWORD` (auth-DB viewer, hasWriteAccess=false) * and the admin storageState from `auth.setup.ts`. * * Uses a nonexistent face id so the *write-access* gate is what's being * proven, not a real mutation: the route checks `hasWriteAccess` before * loading the face, so viewer never reaches the 404 branch. */ const nonExistentFaceId = 999999999; const viewerReady = Boolean(process.env.E2E_VIEWER_EMAIL && process.env.E2E_VIEWER_PASSWORD); test.describe('viewer write gates (NextAuth, viewer) @smoke', () => { test.use({ storageState: path.join(__dirname, '../.auth/viewer.json') }); test.skip(!viewerReady, 'E2E_VIEWER_EMAIL/PASSWORD required'); test('viewer without write access is denied on POST /api/faces/{id}/identify', async ({ page, playkitConfig, timings, }) => { const res = await timings.measure('viewer_identify', () => page.request.post(`${playkitConfig.baseUrl}/api/faces/${nonExistentFaceId}/identify`, { data: { firstName: 'Test', lastName: 'Viewer' }, }), ); expect(res.status()).toBe(403); const body = await res.json(); expect(body).toMatchObject({ error: expect.stringMatching(/write access/i) }); }); }); test.describe('viewer write gates (NextAuth, admin) @smoke', () => { test.use({ storageState: path.join(__dirname, '../.auth/admin.json') }); test('admin (write access) passes the gate on POST /api/faces/{id}/identify', async ({ page, playkitConfig, timings, }) => { const res = await timings.measure('admin_identify', () => page.request.post(`${playkitConfig.baseUrl}/api/faces/${nonExistentFaceId}/identify`, { data: { firstName: 'Test', lastName: 'Admin' }, }), ); // Admin clears the write-access gate; a nonexistent face id then 404s — // proves the gate didn't block a legitimate write-access user. expect(res.status()).toBe(404); const body = await res.json(); expect(body).toMatchObject({ error: expect.stringMatching(/face not found/i) }); }); });