// Fixture-only installation review. All API calls are intercepted; no backups are restored. const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const { chromium } = require(process.env.REVIEW_PLAYWRIGHT || 'playwright'); const base = process.env.REVIEW_BASE || 'http://127.0.0.1:3114'; const output = process.env.REVIEW_DIR; async function reviewBackups(browser) { const context = await browser.newContext({ acceptDownloads: true }); try { await context.addCookies([{ name: 'magent_logged_in', value: '1', url: base }]); const calls = []; const errors = []; let role = 'admin'; let failStatus = false; let failRestore = false; const backup = { created_at: '2026-09-18T01:00:00Z', build: 'fixture-build', include_cache: true }; const status = { format_version: 1, max_upload_bytes: 1024, max_expanded_bytes: 134217728, include_cache_default: false, pending_restore: null, last_restore: null, }; await context.route('**/api/**', async (route) => { const request = route.request(); const pathname = new URL(request.url()).pathname; const method = request.method(); const json = request.headers()['content-type']?.includes('application/json') ? request.postDataJSON() : null; calls.push({ pathname, method, json, body: request.postDataBuffer() }); const reply = (value) => route.fulfill({ json: value }); if (pathname === '/api/setup/status') return reply({ setup_required: false, needs_admin: false }); if (pathname === '/api/auth/me') { return reply({ username: 'Fixture admin', role, features: {}, invite_management_enabled: true }); } if (pathname.startsWith('/api/admin/backups')) { if (role !== 'admin') { return route.fulfill({ status: role === 'unauthorized' ? 401 : 403, json: { detail: 'Admin access required.' } }); } if (pathname === '/api/admin/backups' && method === 'GET') { if (failStatus) return route.fulfill({ status: 503, json: { detail: 'Backup service unavailable.' } }); return reply(status); } if (pathname === '/api/admin/backups/export' && method === 'POST') { return route.fulfill({ contentType: 'application/octet-stream', headers: { 'Content-Disposition': 'attachment; filename="magent-backup-fixture.magent-backup"' }, body: Buffer.from('fixture-only-backup-download'), }); } if (pathname === '/api/admin/backups/restore' && method === 'POST') { if (failRestore) return route.fulfill({ status: 400, json: { detail: 'Invalid backup or passphrase.' } }); status.pending_restore = { ...backup, staged_at: '2026-09-18T02:00:00Z' }; return reply({ status: 'staged', restart_required: true, backup, message: 'Restart to apply.' }); } if (pathname === '/api/admin/backups/restore' && method === 'DELETE') { status.pending_restore = null; return reply({ status: 'cancelled' }); } throw new Error(`Unexpected backup API call: ${method} ${pathname}`); } if (pathname.includes('/events/stream')) { return route.fulfill({ contentType: 'text/event-stream', body: ': fixture\n\n' }); } if (pathname.includes('/branding/')) return route.fulfill({ status: 404 }); return reply({ items: [], total: 0, services: [], navigation: { showRequests: true } }); }); const page = await context.newPage(); page.on('pageerror', (error) => errors.push(error.message)); const exportPanel = page.getByRole('region', { name: 'Create a backup', exact: true }); const restorePanel = page.getByRole('region', { name: 'Restore a backup', exact: true }); const exportCalls = () => calls.filter((call) => call.pathname === '/api/admin/backups/export'); const restoreCalls = () => calls.filter((call) => call.pathname === '/api/admin/backups/restore' && call.method === 'POST'); const screenshot = async (name) => { if (output) await page.screenshot({ path: path.join(output, name), fullPage: true }); }; for (const width of [1440, 980, 390, 320]) { await page.setViewportSize({ width, height: 1000 }); await page.goto(`${base}/admin/backups`); await exportPanel.getByRole('button', { name: 'Download encrypted backup', exact: true }).waitFor(); assert.equal(await exportPanel.getByLabel('Include artwork caches', { exact: true }).isChecked(), false); assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), `Backups overflow at ${width}px`); await screenshot(`installation-backups-${width}.png`); } await page.setViewportSize({ width: 1440, height: 1000 }); await exportPanel.getByLabel('Backup passphrase', { exact: true }).fill('fixture-passphrase-alpha'); await exportPanel.getByLabel('Confirm backup passphrase', { exact: true }).fill('fixture-passphrase-other'); await exportPanel.getByRole('button', { name: 'Download encrypted backup', exact: true }).click(); await page.getByRole('alert').filter({ hasText: 'passphrases do not match' }).waitFor(); assert.equal(exportCalls().length, 0, 'Mismatched passphrases must not request a backup'); await exportPanel.getByLabel('Confirm backup passphrase', { exact: true }).fill('fixture-passphrase-alpha'); await exportPanel.getByLabel('Include artwork caches', { exact: true }).check(); const [download] = await Promise.all([ page.waitForEvent('download'), exportPanel.getByRole('button', { name: 'Download encrypted backup', exact: true }).click(), ]); assert.equal(download.suggestedFilename(), 'magent-backup-fixture.magent-backup'); await page.getByRole('status').filter({ hasText: 'encrypted backup is ready' }).waitFor(); assert.deepEqual(exportCalls().map((call) => call.json), [{ passphrase: 'fixture-passphrase-alpha', include_cache: true }]); assert.equal(await exportPanel.getByLabel('Backup passphrase', { exact: true }).inputValue(), ''); assert.equal(await exportPanel.getByLabel('Confirm backup passphrase', { exact: true }).inputValue(), ''); const upload = restorePanel.getByLabel('Backup file', { exact: true }); const confirmation = restorePanel.getByLabel('Type RESTORE to confirm replacement', { exact: true }); const prepare = restorePanel.getByRole('button', { name: 'Prepare restore', exact: true }); await restorePanel.getByLabel('Backup passphrase', { exact: true }).fill('fixture-passphrase-alpha'); await confirmation.fill('RESTORE'); await upload.setInputFiles({ name: 'empty.magent-backup', mimeType: 'application/octet-stream', buffer: Buffer.alloc(0) }); await prepare.click(); await page.getByRole('alert').filter({ hasText: 'Choose a Magent backup file' }).waitFor(); assert.equal(restoreCalls().length, 0, 'Empty files must not be uploaded'); await upload.setInputFiles({ name: 'oversize.magent-backup', mimeType: 'application/octet-stream', buffer: Buffer.alloc(1025) }); await prepare.click(); await page.getByRole('alert').filter({ hasText: 'no larger than' }).waitFor(); assert.equal(restoreCalls().length, 0, 'Files exceeding the server limit must not be uploaded'); const fixtureFile = { name: 'fixture.magent-backup', mimeType: 'application/octet-stream', buffer: Buffer.from('fixture-backup-upload') }; await upload.setInputFiles(fixtureFile); await confirmation.fill('restore'); await prepare.click(); assert.equal(await confirmation.evaluate((element) => element.validity.patternMismatch), true); assert.equal(restoreCalls().length, 0, 'RESTORE must be typed exactly before uploading'); await confirmation.fill('RESTORE'); failRestore = true; await prepare.click(); await page.getByRole('alert').filter({ hasText: 'Invalid backup or passphrase.' }).waitFor(); assert.equal(await page.getByRole('heading', { name: 'Restore ready — restart required', exact: true }).count(), 0); assert.equal(await prepare.isEnabled(), true, 'A rejected backup must leave the form usable'); failRestore = false; await prepare.click(); await page.getByRole('heading', { name: 'Restore ready — restart required', exact: true }).waitFor(); assert.equal(restoreCalls().length, 2); const submitted = restoreCalls()[1].body.toString('utf8'); assert.match(submitted, /name="file"; filename="fixture\.magent-backup"/); assert.match(submitted, /name="passphrase"\r\n\r\nfixture-passphrase-alpha/); assert.match(submitted, /name="confirmation"\r\n\r\nRESTORE/); assert.equal(await prepare.isDisabled(), true, 'A pending restore must block a second upload'); assert.equal(await restorePanel.getByLabel('Backup passphrase', { exact: true }).inputValue(), ''); assert.equal(await confirmation.inputValue(), ''); assert.equal(await upload.evaluate((element) => element.files.length), 0); await screenshot('installation-backups-pending.png'); await page.reload(); await page.getByRole('heading', { name: 'Restore ready — restart required', exact: true }).waitFor(); assert.equal(await prepare.isDisabled(), true, 'Pending state must survive reloading the page'); await page.getByRole('button', { name: 'Cancel pending restore', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Pending restore cancelled.' }).waitFor(); assert.equal(await page.getByRole('heading', { name: 'Restore ready — restart required', exact: true }).count(), 0); assert.equal(await prepare.isEnabled(), true); assert.equal(calls.filter((call) => call.pathname === '/api/admin/backups/restore' && call.method === 'DELETE').length, 1); failStatus = true; await page.reload(); await page.getByRole('alert').filter({ hasText: 'Backup service unavailable.' }).waitFor(); assert.equal(await exportPanel.count(), 0, 'Backup controls must not render without authenticated status'); failStatus = false; await page.getByRole('button', { name: 'Try again', exact: true }).click(); await exportPanel.getByRole('button', { name: 'Download encrypted backup', exact: true }).waitFor(); status.last_restore = { status: 'rolled_back', restored_at: '2026-09-18T04:00:00Z', rollback_directory: 'fixture-rollback', message: 'An interrupted or failed restore was rolled back automatically.', }; await page.reload(); await page.getByText(/Last restore was rolled back/).waitFor(); assert.equal(await page.getByText(/Last restore completed/).count(), 0, 'A rollback must not be labelled a successful restore'); role = 'user'; await page.goto(`${base}/admin/backups`); await page.getByRole('heading', { name: 'Administrator access required', exact: true }).waitFor(); assert.equal(await page.getByRole('heading', { name: 'Create a backup', exact: true }).count(), 0); role = 'unauthorized'; await page.goto(`${base}/admin/backups`); await page.getByRole('heading', { name: 'Administrator access required', exact: true }).waitFor(); assert.equal(await page.getByRole('link', { name: 'Sign in', exact: true }).getAttribute('href'), '/login'); assert.deepEqual(errors, []); assert.equal(calls.some((call) => /restart/.test(call.pathname)), false, 'Preparing a restore must not restart the app'); console.log('Backup UI passed: responsive layouts, passphrase confirmation, encrypted download, file bounds, RESTORE confirmation, rejected backup retry, pending/cancel state, and admin access.'); } finally { await context.close(); } } async function reviewSetup(browser) { const context = await browser.newContext(); try { const calls = []; const errors = []; const securityErrors = []; let authenticated = false; let role = 'admin'; let needsAdmin = true; let failBootstrap = false; let failComplete = false; let expireNextSave = false; let expectedLoginPassword = 'Fixture-administrator-passphrase'; const state = { completed: false, step: 'administrator', completed_at: null }; const settings = new Map(Object.entries({ site_login_show_local_login: true, site_login_show_jellyfin_login: false, site_login_show_signup_link: true, magent_notify_email_use_tls: true, magent_notify_email_use_ssl: false, magent_notify_email_smtp_port: 587, requests_poll_interval_seconds: 30, requests_delta_sync_interval_minutes: 15, requests_full_sync_time: '03:00', requests_cleanup_days: 30, })); const secret = (key) => key.endsWith('_api_key') || key.endsWith('_password'); await context.route('**/api/**', async (route) => { const request = route.request(); const pathname = new URL(request.url()).pathname; const method = request.method(); const json = request.headers()['content-type']?.includes('application/json') ? request.postDataJSON() : null; calls.push({ pathname, method, json, body: request.postData() }); const reply = (value) => route.fulfill({ json: value }); if (pathname === '/api/setup/status') return reply({ setup_required: !state.completed, needs_admin: needsAdmin }); if (pathname === '/api/setup/bootstrap') { if (failBootstrap) return route.fulfill({ status: 403, json: { detail: 'Invalid setup token.' } }); assert.equal(needsAdmin, true, 'An existing administrator must never be recreated'); needsAdmin = false; state.step = 'apps'; return route.fulfill({ status: 201, json: { status: 'created', username: json.username } }); } if (pathname === '/api/auth/login') { const credentials = new URLSearchParams(request.postData()); assert.equal(credentials.get('username'), 'fixture-admin'); assert.equal(credentials.get('password'), expectedLoginPassword); authenticated = true; return reply({ authenticated: true, user: { role } }); } if (pathname === '/api/auth/logout') { authenticated = false; return reply({ status: 'ok' }); } if (pathname === '/api/auth/me') { return authenticated ? reply({ username: 'Fixture admin', role, features: {}, invite_management_enabled: true }) : route.fulfill({ status: 401, json: { detail: 'Not authenticated.' } }); } if (pathname === '/api/admin/settings' && method === 'PUT' && expireNextSave) { expireNextSave = false; authenticated = false; return route.fulfill({ status: 401, json: { detail: 'Session expired.' } }); } if (pathname === '/api/setup/state' || pathname === '/api/setup/complete' || pathname.startsWith('/api/admin/')) { assert.equal(authenticated, true, `Unauthenticated access attempted: ${pathname}`); assert.equal(role, 'admin', `Non-admin access attempted: ${pathname}`); } if (pathname === '/api/setup/state') { if (method === 'PUT') state.step = json.step; return reply(state); } if (pathname === '/api/setup/complete') { if (failComplete) return route.fulfill({ status: 503, json: { detail: 'Could not finish setup. Please retry.' } }); state.completed = true; state.completed_at = '2026-09-18T03:00:00Z'; return reply(state); } if (pathname === '/api/admin/settings') { if (method === 'PUT') for (const [key, value] of Object.entries(json)) settings.set(key, value); return reply({ settings: Array.from(settings, ([key, value]) => ({ key, value: secret(key) ? '********' : value, sensitive: secret(key), isSet: value !== '' && value !== null, })) }); } if (/\/status\/services\/[^/]+\/test$/.test(pathname)) return reply({ status: 'up', message: 'Fixture connection succeeded.' }); if (/\/admin\/(sonarr|radarr)\/options$/.test(pathname)) { return reply({ rootFolders: [{ path: '/library/tv' }], qualityProfiles: [{ id: 8, name: 'HD 1080p' }] }); } if (pathname.includes('/events/stream')) return route.fulfill({ contentType: 'text/event-stream', body: ': fixture\n\n' }); if (pathname.includes('/branding/')) return route.fulfill({ status: 404 }); return reply({ items: [], total: 0, services: [], navigation: { showRequests: true } }); }); const page = await context.newPage(); page.on('pageerror', (error) => errors.push(error.message)); page.on('console', (entry) => { if (/content security policy|blocked by cors policy/i.test(entry.text())) securityErrors.push(entry.text()); }); const bootstrapCalls = () => calls.filter((call) => call.pathname === '/api/setup/bootstrap'); const writes = () => calls.filter((call) => call.pathname === '/api/admin/settings' && call.method === 'PUT'); const screenshot = async (name) => { assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth), `Setup overflow: ${name}`); if (output) await page.screenshot({ path: path.join(output, name), fullPage: true }); }; const appPanel = (name) => page.locator('details').filter({ has: page.getByText(name, { exact: true }) }); const continueButton = page.getByRole('button', { name: 'Save & continue', exact: true }); await page.goto(`${base}/welcome`); await page.waitForURL(`${base}/setup`); await page.getByRole('heading', { name: 'Create your administrator', exact: true }).waitFor(); assert.equal(await page.locator('.header').count(), 0, 'Setup must not display account navigation before installation'); for (const width of [1440, 390, 320]) { await page.setViewportSize({ width, height: 1000 }); await screenshot(`installation-administrator-${width}.png`); } await page.getByLabel('Setup token', { exact: true }).fill('fixture-operator-token-0123456789abcdef'); await page.getByLabel('Username', { exact: true }).fill('fixture-admin'); await page.getByLabel('Password', { exact: true }).fill(' Fixture-administrator-passphrase '); await page.getByLabel('Confirm password', { exact: true }).fill('Different-administrator-passphrase'); await page.getByRole('button', { name: 'Create administrator', exact: true }).click(); await page.getByRole('alert').filter({ hasText: 'passwords do not match' }).waitFor(); assert.equal(bootstrapCalls().length, 0); await page.getByLabel('Confirm password', { exact: true }).fill(' Fixture-administrator-passphrase '); failBootstrap = true; await page.getByRole('button', { name: 'Create administrator', exact: true }).click(); await page.getByRole('alert').filter({ hasText: 'Invalid setup token.' }).waitFor(); assert.equal(authenticated, false); failBootstrap = false; await page.getByRole('button', { name: 'Create administrator', exact: true }).click(); await page.getByRole('heading', { name: 'Connect your apps', exact: true }).waitFor(); assert.equal(bootstrapCalls().length, 2); assert.equal(needsAdmin, false); assert.equal((await context.cookies()).some((cookie) => cookie.name === 'magent_logged_in'), true); assert.equal(await page.getByLabel('Setup token', { exact: true }).count(), 0); assert.equal(await page.getByRole('link', { name: 'Restore it here', exact: true }).getAttribute('href'), '/admin/backups'); assert.equal(await page.locator('details').count(), 8, 'Every supported app must appear'); for (const width of [1440, 390, 320]) { await page.setViewportSize({ width, height: 1000 }); await screenshot(`installation-apps-${width}.png`); } const jellyfin = appPanel('Jellyfin'); await jellyfin.locator('summary').click(); await jellyfin.getByLabel('Server URL', { exact: true }).fill('jellyfin:8096'); await jellyfin.getByRole('button', { name: 'Save & test Jellyfin', exact: true }).click(); await page.getByRole('alert').filter({ hasText: 'HTTP or HTTPS URL' }).waitFor(); assert.equal(writes().length, 0, 'Save and test must validate URLs without relying on native submit validation'); await page.getByRole('navigation', { name: 'Setup steps', exact: true }).getByRole('button', { name: 'Preferences' }).click(); await page.getByRole('alert').filter({ hasText: 'HTTP or HTTPS URL' }).waitFor(); assert.equal(writes().length, 0, 'Step navigation must validate URL drafts too'); await jellyfin.getByLabel('Server URL', { exact: true }).fill('http://jellyfin:8096'); await jellyfin.getByLabel('API key', { exact: true }).fill('fixture-jellyfin-secret'); await jellyfin.getByLabel('Public playback URL', { exact: true }).fill('https://watch.example.test'); await jellyfin.getByRole('button', { name: 'Save & test Jellyfin', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Jellyfin: Connected' }).waitFor(); assert.deepEqual(writes()[0].json, { jellyfin_base_url: 'http://jellyfin:8096', jellyfin_api_key: 'fixture-jellyfin-secret', jellyfin_public_url: 'https://watch.example.test', }); assert.equal(await page.locator('#setup-jellyfin_api_key').inputValue(), '', 'Saved API keys must not be echoed into the form'); assert.match(await page.locator('#setup-jellyfin_api_key').getAttribute('placeholder'), /Leave blank to keep/); await jellyfin.getByLabel('Public playback URL', { exact: true }).fill('https://new-watch.example.test'); await jellyfin.getByRole('button', { name: 'Save & test Jellyfin', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Jellyfin: Connected' }).waitFor(); assert.deepEqual(writes()[1].json, { jellyfin_public_url: 'https://new-watch.example.test' }); assert.equal(settings.get('jellyfin_api_key'), 'fixture-jellyfin-secret', 'Blank secret fields must preserve credentials'); await screenshot('installation-jellyfin-320.png'); const sonarr = appPanel('Sonarr'); await sonarr.locator('summary').click(); await sonarr.getByLabel('Server URL', { exact: true }).fill('http://sonarr:8989'); await sonarr.getByLabel('API key', { exact: true }).fill('fixture-sonarr-secret'); await sonarr.getByRole('button', { name: 'Save & test Sonarr', exact: true }).click(); await sonarr.getByRole('combobox', { name: 'Quality profile ID', exact: true }).selectOption('8'); await sonarr.getByLabel('Root folder', { exact: true }).fill('/library/tv'); await continueButton.click(); await page.getByRole('heading', { name: 'Choose your preferences', exact: true }).waitFor(); assert.equal(settings.get('sonarr_quality_profile_id'), 8); assert.equal(settings.get('sonarr_root_folder'), '/library/tv'); assert.equal(state.step, 'preferences'); await page.reload(); await page.getByRole('heading', { name: 'Choose your preferences', exact: true }).waitFor(); assert.equal(bootstrapCalls().length, 2, 'Reloading must resume without recreating an administrator'); assert.equal(await page.getByLabel('Show Magent account sign-in', { exact: true }).isChecked(), true); for (const width of [1440, 390, 320]) { await page.setViewportSize({ width, height: 1000 }); await screenshot(`installation-preferences-${width}.png`); } await page.getByLabel('Show Magent account sign-in', { exact: true }).uncheck(); const writesBeforeInvalidPreferences = writes().length; await continueButton.click(); await page.getByRole('alert').filter({ hasText: 'at least one sign-in method' }).waitFor(); assert.equal(writes().length, writesBeforeInvalidPreferences); await page.getByLabel('Show Magent account sign-in', { exact: true }).check(); await page.getByLabel('Use implicit TLS (usually port 465)', { exact: true }).check(); await continueButton.click(); await page.getByRole('alert').filter({ hasText: 'Choose STARTTLS or implicit TLS' }).waitFor(); assert.equal(writes().length, writesBeforeInvalidPreferences); await page.getByLabel('Use implicit TLS (usually port 465)', { exact: true }).uncheck(); await page.getByLabel('Public Magent URL', { exact: true }).fill('https://magent.example.test'); await page.getByLabel('Login page message', { exact: true }).fill('Welcome to the fixture installation.'); await continueButton.click(); await page.getByRole('heading', { name: 'Ready to finish?', exact: true }).waitFor(); assert.equal(state.step, 'review'); assert.equal(settings.get('magent_application_url'), 'https://magent.example.test'); assert.equal(settings.get('site_login_message'), 'Welcome to the fixture installation.'); const finish = page.getByRole('button', { name: 'Finish setup', exact: true }); assert.equal(await finish.isDisabled(), true, 'Setup must not complete without explicit review confirmation'); for (const width of [1440, 390, 320]) { await page.setViewportSize({ width, height: 1000 }); await screenshot(`installation-review-${width}.png`); } await page.getByLabel('I have reviewed the connections and want to finish setup.', { exact: true }).check(); failComplete = true; await finish.click(); await page.getByRole('alert').filter({ hasText: 'Could not finish setup. Please retry.' }).waitFor(); assert.equal(state.completed, false); failComplete = false; await finish.click(); await page.waitForURL(`${base}/admin`); await page.getByRole('heading', { name: 'Settings', exact: true }).waitFor(); assert.equal(state.completed, true); assert.equal(calls.filter((call) => call.pathname === '/api/setup/complete').length, 2); await page.goto(`${base}/setup`); await page.getByText(/This installation is already set up/).waitFor(); await page.getByRole('heading', { name: 'Connect your apps', exact: true }).waitFor(); await appPanel('Jellyfin').locator('summary').click(); assert.equal(await page.locator('#setup-jellyfin_api_key').inputValue(), ''); assert.equal(bootstrapCalls().length, 2); await appPanel('Jellyfin').getByLabel('Public playback URL', { exact: true }).fill('https://after-expiry.example.test'); expireNextSave = true; await appPanel('Jellyfin').getByRole('button', { name: 'Save & test Jellyfin', exact: true }).click(); await page.getByRole('heading', { name: 'Sign in to continue', exact: true }).waitFor(); await page.getByRole('alert').filter({ hasText: 'Your session expired.' }).waitFor(); await page.getByLabel('Username', { exact: true }).fill('fixture-admin'); await page.getByLabel('Password', { exact: true }).fill(expectedLoginPassword); await page.getByRole('button', { name: 'Sign in to continue', exact: true }).click(); await page.getByRole('heading', { name: 'Connect your apps', exact: true }).waitFor(); await appPanel('Jellyfin').locator('summary').click(); assert.equal(await appPanel('Jellyfin').getByLabel('Public playback URL', { exact: true }).inputValue(), 'https://after-expiry.example.test'); await appPanel('Jellyfin').getByRole('button', { name: 'Save & test Jellyfin', exact: true }).click(); await page.getByRole('status').filter({ hasText: 'Jellyfin: Connected' }).waitFor(); assert.equal(settings.get('jellyfin_public_url'), 'https://after-expiry.example.test'); await context.clearCookies(); authenticated = false; await page.goto(`${base}/setup`); await page.getByRole('heading', { name: 'Sign in to continue', exact: true }).waitFor(); assert.equal(await page.getByLabel('Setup token', { exact: true }).count(), 0); await page.getByLabel('Username', { exact: true }).fill('fixture-admin'); await page.getByLabel('Password', { exact: true }).fill('Fixture-administrator-passphrase'); await page.getByRole('button', { name: 'Sign in to continue', exact: true }).click(); await page.getByRole('heading', { name: 'Connect your apps', exact: true }).waitFor(); const protectedReads = calls.filter((call) => ['/api/setup/state', '/api/admin/settings'].includes(call.pathname)).length; role = 'user'; state.completed = false; await page.goto(`${base}/setup`); await page.getByRole('heading', { name: 'Administrator access required', exact: true }).waitFor(); assert.equal(await page.getByRole('navigation', { name: 'Setup steps', exact: true }).count(), 0); assert.equal(calls.filter((call) => ['/api/setup/state', '/api/admin/settings'].includes(call.pathname)).length, protectedReads); await page.getByRole('button', { name: 'Sign in with an administrator account', exact: true }).click(); await page.getByRole('heading', { name: 'Sign in to continue', exact: true }).waitFor(); assert.equal(page.url(), `${base}/setup`, 'Switching accounts on an unfinished install must avoid the login redirect loop'); role = 'admin'; expectedLoginPassword = ' Existing-administrator-passphrase '; await page.getByLabel('Username', { exact: true }).fill('fixture-admin'); await page.getByLabel('Password', { exact: true }).fill(expectedLoginPassword); await page.getByRole('button', { name: 'Sign in to continue', exact: true }).click(); await page.getByRole('heading', { name: 'Ready to finish?', exact: true }).waitFor(); assert.deepEqual(errors, []); assert.deepEqual(securityErrors, [], 'Setup must hydrate without CSP or CORS errors'); console.log('Setup UI passed: fresh-install redirect, token/password checks, bootstrap/login, app save/test, masked credentials, collector choices, preferences validation, resume, finish/retry, existing installs, and admin-only access.'); } finally { await context.close(); } } (async () => { if (output) fs.mkdirSync(output, { recursive: true }); const browser = await chromium.launch({ headless: true, executablePath: process.env.REVIEW_CHROMIUM || undefined }); try { await reviewBackups(browser); await reviewSetup(browser); } finally { await browser.close(); } })().catch((error) => { console.error(error); process.exitCode = 1; });