import assert from 'node:assert/strict' import { chromium } from 'playwright' const baseUrl = process.env.D3RO_ADMIN_E2E_URL?.trim() ?? '' if (!baseUrl.startsWith('https://127.0.0.1:')) throw new Error('Local HTTPS admin E2E URL is required') const browser = await chromium.launch({ headless: true }) const page = await browser.newPage({ viewport: { width: 1440, height: 1000 }, ignoreHTTPSErrors: true }) await page.addInitScript(() => { window.alert = () => undefined window.confirm = () => true window.prompt = () => 'browser verified endpoint deletion' }) const consoleErrors = [] const serverErrors = [] page.on('console', (message) => { if (message.type() === 'error') consoleErrors.push(message.text()) }) page.on('response', (response) => { if (response.status() >= 500) serverErrors.push(`${response.status()} ${response.url()}`) }) try { await page.goto(`${baseUrl}/`, { waitUntil: 'networkidle' }) await page.getByLabel('Admin Identifier (Username / Email)').fill('admin.browser.e2e@example.com') await page.getByLabel('Password').fill('Admin-browser-e2e-strong-password!') await Promise.all([ page.waitForURL(`${baseUrl}/`), page.getByRole('button', { name: 'Sign In as Super Admin' }).click() ]) await page.getByText('BACKEND CONNECTED').waitFor() const endpointPayload = await page.evaluate(async () => { const response = await fetch('/api/admin/backend/endpoints', { cache: 'no-store' }) return { status: response.status, body: await response.json() } }) assert.equal(endpointPayload.status, 200) assert.ok(Array.isArray(endpointPayload.body)) assert.ok(endpointPayload.body.every((endpoint) => endpoint.apiKey === '' || endpoint.apiKey === '••••••••')) await page.goto(`${baseUrl}/models`, { waitUntil: 'networkidle' }) await page.getByRole('tab', { name: /LLM & Reasoning Model Endpoints/ }).click() const addModelButton = page.getByRole('button', { name: /Add LLM Model Endpoint/ }) if (await addModelButton.count() === 0) { const cookies = await page.context().cookies() const bodyText = (await page.locator('body').innerText()).slice(0, 1200) throw new Error(`models diagnostic url=${page.url()} cookies=${cookies.map((cookie) => `${cookie.name}:${cookie.secure}:${cookie.sameSite}`).join(',')} body=${bodyText}`) } await addModelButton.click() await page.getByLabel('Model ID').fill('browser-e2e-model') await page.getByLabel('Display Name').fill('Browser E2E Model') await page.getByLabel('Endpoint URL').fill('https://models.example.com/v1') await page.getByLabel('Audit memo').last().fill('browser verified endpoint creation') const createResponse = page.waitForResponse((response) => response.url().includes('/api/admin/backend/endpoints') && response.request().method() === 'POST') await page.getByRole('button', { name: 'Save Endpoint' }).click() const created = await createResponse assert.equal(created.status(), 200, `model creation failed: ${await created.text()}`) await page.getByText('Browser E2E Model').waitFor() const modelRow = page.locator('tr').filter({ hasText: 'browser-e2e-model' }) const deleteResponse = page.waitForResponse((response) => response.url().includes('/api/admin/backend/endpoints/') && response.request().method() === 'DELETE') await modelRow.getByRole('button', { name: 'Delete' }).click() const deleted = await deleteResponse assert.equal(deleted.status(), 200, `model deletion failed: ${await deleted.text()}`) await page.getByText('Browser E2E Model').waitFor({ state: 'detached' }) await page.goto(`${baseUrl}/users`, { waitUntil: 'networkidle' }) const customerRow = page.locator('tr').filter({ hasText: 'customer.browser.e2e@example.com' }) await customerRow.waitFor() const customerHref = await customerRow.getByRole('link').first().getAttribute('href') assert.match(customerHref ?? '', /^\/users\/[0-9a-f-]{36}$/) const customerId = customerHref.split('/').pop() await page.goto(`${baseUrl}${customerHref}`, { waitUntil: 'networkidle' }) await page.getByRole('button', { name: 'Change Role' }).click() const roleDialog = page.getByRole('dialog', { name: /CHANGE USER ROLE/ }) await roleDialog.waitFor() await roleDialog.getByRole('combobox').click() await page.getByRole('option', { name: 'manager' }).click() await page.getByPlaceholder('Reason for role change (required)...').fill('browser verified support assignment') await page.getByRole('button', { name: 'Change Role', exact: true }).last().click() await page.getByText('MANAGER').first().waitFor() await page.goto(`${baseUrl}/subscriptions/${customerId}`, { waitUntil: 'networkidle' }) await page.getByRole('combobox', { name: 'Tier' }).click() await page.getByRole('option', { name: 'PRO', exact: true }).click() await page.getByLabel('Memo (required for audit log)').fill('browser verified subscription update') await page.getByRole('button', { name: 'Update' }).click() await page.getByText('Operation successful').waitFor() await page.goto(`${baseUrl}/audit-log`, { waitUntil: 'networkidle' }) await page.getByText('user.role_change').first().waitFor() await page.getByText('subscription.update').first().waitFor() await page.screenshot({ path: 'scratch/admin-browser-e2e.png', fullPage: true }) assert.deepEqual(serverErrors, [], `server errors: ${serverErrors.join(', ')}`) assert.deepEqual(consoleErrors, [], `console errors: ${consoleErrors.join(', ')}`) console.log('admin browser E2E: login, JWT proxy, model create/delete, users, role, subscription, audit GREEN') } finally { await browser.close() }