import { test, expect, type APIRequestContext } from '../../../../../job-tracker-ui/node_modules/@playwright/test'; import os from 'node:os'; const api = 'http://localhost:5302/api'; const password = 'E2ePassword123!'; async function login(request: APIRequestContext, email: string) { expect((await request.post(`${api}/auth/login`, { data: { email, password } })).status()).toBe(200); const me = await (await request.get(`${api}/auth/me`)).json(); const csrf = (await request.storageState()).cookies.find(cookie => cookie.name === 'XSRF-TOKEN')!.value; return { 'X-CSRF-TOKEN': csrf, 'X-Session-Context': me.sessionContext as string }; } test('P9 bounded sustained reads with 250 jobs and long CV while using native workspaces', async ({ page, context, playwright }, info) => { test.setTimeout(240000); const admin = await playwright.request.newContext(); const latency: { worker: number; endpoint: string; ms: number; bytes: number; status: number }[] = []; const navigation: object[] = []; const cdp = await context.newCDPSession(page); await cdp.send('Performance.enable'); try { const adminHeaders = await login(admin, 'e2e@example.test'); const email = `p9-sustained-${Date.now()}@example.test`; expect((await admin.post(`${api}/users`, { headers: adminHeaders, data: { email, password, roles: ['Premium'] } })).status()).toBe(200); const headers = await login(page.request, email); const company = await page.request.post(`${api}/companies`, { headers, data: { name: 'P9 bounded workload' } }); expect(company.status()).toBe(201); const companyId = (await company.json()).id; for (let index = 0; index < 250; index++) expect((await page.request.post(`${api}/jobapplications`, { headers, data: { companyId, jobTitle: `P9 bounded role ${index}`, status: 'Applied', dateApplied: new Date().toISOString() } })).status()).toBe(201); const profile = { version: '1', contact: { fullName: 'Åse Synthetic', email: 'synthetic@example.test' }, summary: ['Documented accessible workflows.'], jobs: Array.from({ length: 8 }, (_, index) => ({ id: `p9-role-${index}`, title: `Platform engineer ${index}`, company: 'Nordlys synthetic', start: '2017-01', end: '2025-12', bullets: Array.from({ length: 6 }, (_, bullet) => `Evidence ${index}.${bullet}: ${'Documented reliable workflows. Dokumenterte pålitelige arbeidsflyter. '.repeat(3).trim()}`) })) }; expect((await page.request.put(`${api}/career/profile`, { headers, data: { profile } })).status()).toBe(200); const savedProfile = (await (await page.request.get(`${api}/career/profile`)).json()).profile; expect(savedProfile.jobs).toHaveLength(8); expect(savedProfile.jobs.map((job: { start: string; end: string; bullets: string[] }) => ({ start: job.start, end: job.end, bullets: job.bullets }))) .toEqual(profile.jobs.map(job => ({ start: job.start, end: job.end, bullets: job.bullets }))); const cv = await page.request.post(`${api}/cv/variants`, { headers, data: { name: 'P9 long workload CV', settings: { themeId: 'minimal', language: 'nb' } } }); expect(cv.status()).toBe(200); const cvId = (await cv.json()).id; await context.route('**/*', route => { const url = new URL(route.request().url()); return ['localhost', '127.0.0.1'].includes(url.hostname) || ['data:', 'blob:', 'about:'].includes(url.protocol) ? route.continue() : route.abort(); }); const endpoints = ['/jobapplications/stats', '/jobapplications/board', '/career/profile', '/documents']; const started = Date.now(); const readWorker = async (worker: number) => { for (let index = 0; index < 120; index++) { const endpoint = endpoints[index % endpoints.length]; const begin = Date.now(); const response = await page.request.get(`${api}${endpoint}`); latency.push({ worker, endpoint, ms: Date.now() - begin, bytes: (await response.body()).length, status: response.status() }); expect(response.status(), endpoint).toBe(200); if (endpoint.endsWith('/board')) expect(await response.json()).toHaveLength(250); await new Promise(resolve => setTimeout(resolve, 500)); } }; const interact = async () => { for (let cycle = 0; cycle < 5; cycle++) for (const route of ['/dashboard', '/jobs?view=table', '/jobs?view=board', `/career/builder/${cvId}`]) { const begin = Date.now(); await page.goto(route); if (route === '/dashboard') await expect(page.getByRole('link', { name: 'Tracked jobs: 250', exact: true })).toBeVisible(); else if (route.endsWith('board')) await expect(page.locator('[data-kanban-card-id]')).toHaveCount(250); else if (route.endsWith('table')) await expect(page.locator('[data-job-row-id]').first()).toBeVisible(); else { await expect(page.getByRole('region', { name: 'Live preview', exact: true })).toHaveAttribute('aria-busy', 'false'); const measured = await page.getByTitle('CV preview', { exact: true }).evaluate(element => { const doc = (element as HTMLIFrameElement).contentDocument!; const pages = Number(doc.documentElement.dataset.cvPreviewPages); const width = Number(doc.documentElement.dataset.cvPreviewWidth); const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT); let node; let finalMarkerPage = 0; while ((node = walker.nextNode())) { const index = node.textContent?.indexOf('Evidence 7.5:') ?? -1; if (index < 0) continue; const range = doc.createRange(); range.setStart(node, index); range.setEnd(node, index + 'Evidence 7.5:'.length); finalMarkerPage = Math.floor(range.getClientRects()[0].x / width) + 1; } return { pages, finalMarkerPage, ready: doc.documentElement.dataset.cvPreviewReady }; }); expect(measured.ready).toBe('true'); expect(measured.pages).toBeGreaterThan(1); expect(measured.finalMarkerPage).toBe(measured.pages); await expect(page.locator('[data-cv-page]')).toHaveCount(measured.pages); await expect(page.getByTitle('CV preview page 1', { exact: true })).toBeVisible(); } navigation.push({ cycle, route, readyMs: Date.now() - begin, metrics: (await cdp.send('Performance.getMetrics')).metrics, domElements: await page.locator('*').count() }); } }; await Promise.all([readWorker(0), readWorker(1), interact()]); const durationMs = Date.now() - started; expect(durationMs).toBeGreaterThanOrEqual(60000); expect(latency).toHaveLength(240); expect((await (await page.request.get(`${api}/jobapplications/board`)).json())).toHaveLength(250); expect((await (await page.request.get(`${api}/career/profile`)).json()).profile).toEqual(savedProfile); const sorted = latency.map(row => row.ms).sort((a, b) => a - b); await info.attach('phase9-sustained-performance', { body: JSON.stringify({ durationMs, fixtureJobs: 250, fixtureCareerRoles: 8, readConcurrency: 2, reads: latency.length, p50Ms: sorted[Math.floor(sorted.length * .5)], p95Ms: sorted[Math.floor(sorted.length * .95)], maxMs: sorted.at(-1), environment: { platform: os.platform(), cpus: os.cpus().length, totalMemoryBytes: os.totalmem(), browser: context.browser()?.version(), database: 'isolated SQLite', frontend: 'production static export' }, latency, navigation, limits: 'Finite paced two-reader workload plus 20 native navigations; no SLA/capacity, physical mobile, deployed Linux, model inference or server CPU attribution.' }, null, 2), contentType: 'application/json' }); } finally { await cdp.detach(); await admin.dispose(); } });