test(ui): qualify flat administration across responsive locales

This commit is contained in:
cesnimda
2026-11-04 08:48:35 +01:00
parent d651ce7aa4
commit 0e2ccfe984
366 changed files with 5397 additions and 24 deletions
@@ -8,14 +8,16 @@ import path from 'node:path';
const compiled = ts.transpileModule(fs.readFileSync(new URL('../src/i18n/translations.ts', import.meta.url), 'utf8'), { compilerOptions: { module: ts.ModuleKind.ESNext } }).outputText;
const { translations } = await import(`data:text/javascript;base64,${Buffer.from(compiled).toString('base64')}`);
const accountOnly = Boolean(process.env.A3_ACCOUNT_FLAT);
const out = path.resolve(import.meta.dirname, accountOnly ? '../../docs/ui-modernisation/visual-correction/evidence/account-flat' : '../../docs/ui-modernisation/evidence/account-admin/browser');
const adminOnly = Boolean(process.env.A3_ADMIN_FLAT);
const out = path.resolve(import.meta.dirname, adminOnly ? '../../docs/ui-modernisation/visual-correction/evidence/admin-flat' : accountOnly ? '../../docs/ui-modernisation/visual-correction/evidence/account-flat' : '../../docs/ui-modernisation/evidence/account-admin/browser');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], exportDenials: [], unavailableReads: [], blockedExternal: [] };
const browser = await chromium.launch();
const processingOnly = Boolean(process.env.A3_PROCESSING_ONLY);
assert.ok(!(processingOnly && accountOnly), 'Account and processing qualification are distinct scopes.');
assert.ok(!adminOnly || !(processingOnly || accountOnly), 'Admin qualification is a distinct scope.');
try {
const configurations = process.env.A3_PILOT ? [[320, 'en', 'light']] : (accountOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
const configurations = process.env.A3_PILOT ? (adminOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[320, 'en', 'light']]) : (accountOnly || adminOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440]).flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
for (const [width, language, mode] of configurations) {
console.log(`Checking ${width}/${language}/${mode}`);
const t = key => { assert.ok(translations[language][key], key); return translations[language][key]; };
@@ -25,6 +27,17 @@ try {
const session = { id: 'current', deviceLabel: 'Synthetic current device', isCurrentSession: true, createdAtUtc: '2026-11-03T10:00:00Z', lastSeenAtUtc: '2026-11-03T10:00:00Z', expiresAtUtc: '2026-12-03T10:00:00Z' };
const operation = { id: '11111111-1111-4111-8111-111111111111', owner: { id: 'a3-admin-owner', name: 'Alex Sample', email: 'alex@example.test' }, taskType: 'cv.process', status: 'failed', stage: 'cv_extracting', attemptCount: 1, maxAttempts: 3, createdAtUtc: '2026-11-03T10:00:00Z', startedAtUtc: null, completedAtUtc: null, lastHeartbeatAtUtc: null, durationSeconds: 8, worker: 'document', workerEnabled: false, failureCode: 'parser_failed', lastFailureAtUtc: '2026-11-03T10:00:08Z', lastFailureStage: 'cv_extracting', job: { id: 42, title: 'Recorded teacher application', company: 'Synthetic school', canOpen: false }, document: { importId: 7, name: 'Recorded teacher CV.pdf', type: 'application/pdf', bytes: 500, pages: 2, state: 'failed' } };
const listing = { items: [operation], total: 1, counts: { failed: 1 }, workers: [{ name: 'CvDocumentImports', flagEnabled: false, individualOperationsRecorded: true }] };
let populatedAudit = false, systemAvailable = false;
const system = {
environment: 'Synthetic qualification', contentRoot: '/synthetic/app', version: 'fixture', commitSha: 'fixture', buildStamp: '2026-11-04',
storage: { dataRoot: '/synthetic', dbPath: '/synthetic/db', dbExists: true, dbSizeBytes: 2048, companyCount: 3, jobCount: 7, deletedCount: 1 },
email: { enabled: false, host: 'smtp.example.test', port: 587, enableSsl: true, from: 'noreply@example.test', fromName: 'Synthetic' },
database: { provider: 'mariadb', looksConfigured: true, canConnect: true, target: 'synthetic', usesFileStorage: false, warning: null },
runtime: { framework: 'Synthetic .NET', osDescription: 'Fixture', processArchitecture: 'X64', machineName: 'fixture' },
auth: { required: true, hasJwtKey: true, googleConfigured: false, gmailConfigured: false },
ai: { healthy: false, model: null, device: null, gpuAvailable: false, gpuName: null, ocrAvailable: false, ocrLanguages: '', ollamaConfigured: false, ollamaReachable: false, ollamaModel: null, ollamaModelAvailable: false, ollamaVersion: null, ollamaInstalledModels: [], ollamaLoadedModels: [], ollamaLoadedCount: 0, healthLatencyMs: 0, probeLatencyMs: 0, probeFailures: 0, requests: 0, cacheHits: 0, cacheMisses: 0, failures: 0, averageLatencyMs: 0, ocrRequests: 0, ocrFailures: 0, averageOcrLatencyMs: 0, lastError: null },
};
const benchmark = { rootPath: '/synthetic/benchmarks', lastUpdatedAtUtc: '2026-11-04T10:00:00Z', reportMarkdown: '# Synthetic report\n\nFixture only.', indexJson: JSON.stringify({ CorpusRoot: '/synthetic/corpus', OutputRoot: '/synthetic/benchmarks', GeneratedAtUtc: '2026-11-04T10:00:00Z', TotalFiles: 1, AverageCoverage: 0.5, AverageConfidence: 0.65, AverageConsistency: 0.8, FilesWithSuspiciousLocations: 1, MissingApprovedFixtures: 1, Entries: [{ FileName: 'Synthetic-teacher.txt', Slug: 'synthetic-teacher', Extension: '.txt', Characters: 2000, OutputPath: '/synthetic/output.json', ApprovedFixturePath: null, CandidateFixturePath: '/synthetic/candidate.json', ContactLocation: 'Oslo, Hobbies', FirstJob: 'Teacher', FirstEducation: 'Education degree', QualificationLevels: ['Other'], SuspiciousLocations: [], CoverageScore: 0.5, ConfidenceScore: 0.65, ConsistencyScore: 0.8, DiffSummary: 'Synthetic unapproved fixture.' }] }) };
await page.route('**/*', route => {
const req = route.request(), url = new URL(req.url()), p = url.pathname;
if (url.origin !== 'http://localhost:4338' && !(url.origin === 'http://localhost:5202' && p.startsWith('/api/'))) { report.blockedExternal.push(url.origin); return route.abort(); }
@@ -43,10 +56,16 @@ try {
'/api/account-lifecycle/status': { deletionEnabled: true, deletionStatus: 'active', requiredConfirmation: 'DELETE alex@example.test', request: null },
'/api/gmail/status': { connected: false, configured: false }, '/api/microsoft-graph/status': { connected: false, configured: false }, '/api/imap/status': { connected: false, configured: false },
'/api/users': [{ id: 'a3-admin-owner', email: 'alex@example.test', userName: 'alex', emailConfirmed: true, roles: ['Admin'], isCurrentUser: true, canRemoveAdmin: false }],
'/api/admin/audit': [], '/api/admin/processing': listing,
'/api/admin/audit': populatedAudit ? [{ id: 1, type: 'StatusChanged', oldValue: 'Applied', newValue: 'Interview', note: 'Synthetic audit event', at: '2026-11-04T10:00:00Z', jobApplicationId: 42, jobTitle: operation.job.title, companyName: operation.job.company, ownerUserId: 'a3-admin-owner', ownerEmail: 'alex@example.test', ownerUserName: 'alex' }] : [], '/api/admin/processing': listing,
[`/api/admin/processing/${operation.id}`]: operation,
[`/api/admin/processing/${operation.id}/events`]: { items: [{ id: '9007199254740993', atUtc: '2026-11-03T10:00:08Z', kind: 'Failed', status: 'failed', stage: 'cv_extracting', attempt: 1, failureCode: 'parser_failed' }], hasMore: false, retentionDays: 30 },
};
if (systemAvailable) Object.assign(fixtures, {
'/api/admin/system': system,
'/api/admin/system/email-settings': { ...system.email, user: 'mailer@example.test', timeoutMs: 15000, usesOverrides: false, hasPassword: false },
'/api/admin/system/cv-benchmark': benchmark,
'/api/admin/system/maintenance-jobs': [{ id: 'cv-benchmark', title: 'Synthetic benchmark', description: 'Fixture only', available: false, runsUrl: null }],
});
if (Object.hasOwn(fixtures, p)) return answer(fixtures[p]);
report.unavailableReads.push(p); return route.fulfill({ status: 503, contentType: 'application/json', body: JSON.stringify({ detail: 'Controlled offline read unavailable.' }) });
});
@@ -58,6 +77,7 @@ try {
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 && !keepScroll });
};
if (!processingOnly) {
if (!adminOnly) {
await page.goto('http://localhost:4338/profile');
const name = page.getByRole('textbox', { name: t('profileDisplayName'), exact: true }); await expect(name).toHaveValue('Alex Sample'); await name.fill('Unsaved account name');
const nav = page.getByRole('navigation', { name: t('accountWorkspaceNavigation'), exact: true });
@@ -72,10 +92,19 @@ try {
await page.getByRole('button', { name: t('accountExportDownload'), exact: true }).click(); await expect(page.getByText(t('accountExportFailed'), { exact: true })).toBeVisible();
await page.getByRole('button', { name: t('accountDeleteButton'), exact: true }).click(); const deletion = page.getByRole('dialog'); await expect(deletion).toContainText('DELETE alex@example.test'); await scan('data-confirmation'); await deletion.getByRole('button', { name: t('cancel'), exact: true }).click();
await page.goto('http://localhost:4338/settings/connected-accounts'); await expect(page.getByRole('heading', { name: t('connectedAccounts'), exact: true })).toBeVisible(); await scan('connections');
}
if (!accountOnly) {
await page.goto('http://localhost:4338/admin/users'); await expect(page.getByRole('button', { name: t('adminUsersRemoveAdmin'), exact: true })).toBeDisabled(); await expect(page.getByRole('button', { name: t('adminUsersDelete'), exact: true })).toBeDisabled(); await scan('last-admin');
await page.goto('http://localhost:4338/admin/audit'); await expect(page.getByText(t('adminAuditNoEvents'), { exact: true })).toBeVisible(); await scan('audit-empty');
if (adminOnly) { populatedAudit = true; await page.reload(); await expect(page.getByRole('cell', { name: 'Applied -> Interview Synthetic audit event', exact: true })).toBeVisible(); await scan('audit-populated'); }
await page.goto('http://localhost:4338/admin/system'); await expect(page.getByText(t('adminSystemLoadFailed'), { exact: true })).toBeVisible(); await scan('system-unavailable');
if (adminOnly) {
systemAvailable = true; await page.reload(); await expect(page.getByText(system.environment, { exact: true })).toBeVisible(); await scan('system-normal');
const benchmarkHeading = page.getByRole('heading', { name: t('adminBenchmarkTitle'), exact: true });
await benchmarkHeading.evaluate(el => window.scrollBy({ top: el.getBoundingClientRect().top - 90, behavior: 'instant' })); await scan('system-benchmark', true);
await page.getByRole('heading', { name: t('adminBenchmarkTopFindings'), exact: true }).evaluate(el => window.scrollBy({ top: el.getBoundingClientRect().top - 90, behavior: 'instant' })); await scan('system-findings', true);
await page.getByRole('tab', { name: t('adminSystemSettingsTab'), exact: true }).click(); await scan('system-settings');
}
}
}
if (!accountOnly) {
@@ -91,12 +120,12 @@ try {
await page.getByRole('button', { name: t('processingViewDetails').replace('{id}', operation.id), exact: true }).click(); await expect(page.getByRole('heading', { name: t('processingDetails'), exact: true })).toBeFocused();
await expect(page.getByRole('link', { name: operation.job.title, exact: true })).toHaveCount(0); await scan('processing-detail');
}
report.journeys.push({ width, language, mode, draftPreservedAcrossKeyboardSections: processingOnly ? 'NOT RUN' : 'PASS', revocationAndDeletionCancelled: processingOnly ? 'NOT RUN' : 'PASS', recentExportDenial: processingOnly ? 'NOT RUN' : 'PASS', lastAdminActionsDisabled: processingOnly || accountOnly ? 'NOT RUN' : 'PASS', processingKeyboardAndOwnerLink: accountOnly ? 'NOT RUN' : 'PASS', processingFilterLabelsAndDurationGeometry: accountOnly ? 'NOT RUN' : 'PASS' }); await context.close();
report.journeys.push({ width, language, mode, draftPreservedAcrossKeyboardSections: processingOnly || adminOnly ? 'NOT RUN' : 'PASS', revocationAndDeletionCancelled: processingOnly || adminOnly ? 'NOT RUN' : 'PASS', recentExportDenial: processingOnly || adminOnly ? 'NOT RUN' : 'PASS', lastAdminActionsDisabled: processingOnly || accountOnly ? 'NOT RUN' : 'PASS', processingKeyboardAndOwnerLink: accountOnly ? 'NOT RUN' : 'PASS', processingFilterLabelsAndDurationGeometry: accountOnly ? 'NOT RUN' : 'PASS', populatedAdminReadStates: adminOnly ? 'PASS' : 'NOT RUN' }); await context.close();
}
assert.equal(report.screens.length, configurations.length * (accountOnly ? 7 : processingOnly ? 1 : 8)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.exportDenials.length, processingOnly ? 0 : configurations.length);
assert.equal(report.screens.length, configurations.length * (accountOnly ? 7 : processingOnly ? 1 : adminOnly ? 9 : 8)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.exportDenials.length, processingOnly || adminOnly ? 0 : configurations.length);
assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
console.log(`PASS:${report.journeys.length} controlled journeys,${report.screens.length} axe scans/captures; no mutation requests.`);
} finally {
fs.writeFileSync(path.join(out, processingOnly ? 'PROCESSING.json' : process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['Every API response is synthetic. Account export is a controlled 403; revocation/deletion confirmations are cancelled, not executed.', 'System monitor capture is the controlled unavailable state, audit is empty; detailed success/action scenarios are unit tests, not live qualification.', 'No real credentials, provider activation, model, native device, integrated security, production or release acceptance.'] }, null, 2));
fs.writeFileSync(path.join(out, processingOnly ? 'PROCESSING.json' : process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['Every API response is synthetic. In admin-only mode all mutations are blocked and account flows are NOT RUN; otherwise account export is a controlled 403 and confirmations are cancelled.', adminOnly ? 'System and audit populated states are synthetic read fixtures; no probe, maintenance, settings save, undo, restore or provider action executed.' : 'System monitor is unavailable and audit empty; detailed success/action scenarios are unit tests, not live qualification.', 'No real credentials, provider activation, model, native device, integrated security, production or release acceptance.'] }, null, 2));
await browser.close();
}