style(ui): reduce initial dashboard gaps and flatten discovery rows

This commit is contained in:
cesnimda
2026-11-04 01:58:30 +01:00
parent df0ef68cd9
commit a7d726738b
88 changed files with 1748 additions and 20 deletions
+14 -6
View File
@@ -4,12 +4,18 @@ import AxeBuilder from '@axe-core/playwright';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
const out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/dashboard/browser');
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
const widths = process.env.A3_PILOT ? [320] : visualMatrix ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440];
const languages = process.env.A3_PILOT ? ['en'] : ['en', 'nb'];
const modes = process.env.A3_PILOT ? ['light'] : ['light', 'dark'];
const expectedJourneys = widths.length * languages.length * modes.length;
const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/dashboard' : '../../docs/ui-modernisation/evidence/dashboard/browser');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], blockedExternal: [] };
const browser = await chromium.launch();
try {
for (const width of [320, 390, 768, 1440]) for (const language of ['en', 'nb']) for (const mode of ['light', 'dark']) {
for (const width of widths) for (const language of languages) for (const mode of modes) {
console.log(`Checking ${width}/${language}/${mode}`);
const context = await browser.newContext({ viewport: { width, height: 1000 }, reducedMotion: 'reduce' });
const page = await context.newPage(); page.on('pageerror', error => report.errors.push(error.message));
await page.addInitScript(({ language, mode }) => { localStorage.setItem('uiLanguage', language); localStorage.setItem('jobtracker.themeMode', mode); }, { language, mode });
@@ -58,7 +64,7 @@ try {
assert.equal(await week.locator('time').first().getAttribute('datetime'), deadline);
assert.equal(await week.getByRole('link', { name: 'Community nurse' }).count(), 0);
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false);
if (width === 1440) await page.waitForFunction(() => {
if (width >= 1440) await page.waitForFunction(() => {
const a = document.querySelector('[data-dashboard-widget=agenda]').getBoundingClientRect(), b = document.querySelector('[data-dashboard-widget=funnel]').getBoundingClientRect();
return Math.abs(a.top - b.top) < 2 && a.left < b.left;
});
@@ -94,9 +100,11 @@ try {
}
assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []);
assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
assert.equal(report.mockedWrites.length, 16);
console.log('PASS: 16 dashboard journeys,32 scoped axe sweeps,32 captures; controlled API persistence only.');
assert.equal(report.mockedWrites.length, expectedJourneys);
assert.equal(report.journeys.length, expectedJourneys);
assert.equal(report.screens.length, expectedJourneys * 2);
console.log(`PASS:${report.journeys.length} dashboard journeys,${report.screens.length} scoped axe sweeps/captures; controlled API persistence only.`);
} finally {
fs.writeFileSync(path.join(out, 'BROWSER.json'), JSON.stringify({ ...report, limits: ['synthetic API fixtures, not real backend end-to-end','no native device/screen reader/model/provider/security/release qualification'] }, null, 2));
fs.writeFileSync(path.join(out, process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['synthetic API fixtures, not real backend end-to-end','no native device/screen reader/model/provider/security/release qualification'] }, null, 2));
await browser.close();
}
+12 -6
View File
@@ -4,12 +4,18 @@ import AxeBuilder from '@axe-core/playwright';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
const out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/discovery/browser');
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
const widths = process.env.A3_PILOT ? [320] : visualMatrix ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440];
const languages = process.env.A3_PILOT ? ['en'] : ['en', 'nb'];
const modes = process.env.A3_PILOT ? ['light'] : ['light', 'dark'];
const expectedJourneys = widths.length * languages.length * modes.length;
const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/discovery' : '../../docs/ui-modernisation/evidence/discovery/browser');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], blockedExternal: [] };
const browser = await chromium.launch();
try {
for (const width of [320, 390, 768, 1440]) for (const language of ['en', 'nb']) for (const mode of ['light', 'dark']) {
for (const width of widths) for (const language of languages) for (const mode of modes) {
console.log(`Checking ${width}/${language}/${mode}`);
const context = await browser.newContext({ viewport: { width, height: 1000 }, reducedMotion: 'reduce' });
const page = await context.newPage(); page.on('pageerror', error => report.errors.push(error.message));
await page.addInitScript(({ language, mode }) => { localStorage.setItem('uiLanguage', language); localStorage.setItem('jobtracker.themeMode', mode); }, { language, mode });
@@ -50,7 +56,7 @@ try {
const result = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze();
report.screens.push({ width, language, mode, state, violations: result.violations }); assert.deepEqual(result.violations, []);
await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: true });
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 });
};
await page.goto('http://localhost:4338/discover');
const filters = page.getByRole('complementary', { name: language === 'en' ? 'Search filters' : 'Søkefiltre' }); await filters.waitFor();
@@ -84,11 +90,11 @@ try {
report.journeys.push({ width, language, mode, searchSavePauseRunDismissConfirmedDelete: 'PASS' });
await context.close();
}
assert.equal(report.screens.length, 48); assert.equal(report.journeys.length, 16); assert.equal(report.mockedWrites.length, 80);
assert.equal(report.screens.length, expectedJourneys * 3); assert.equal(report.journeys.length, expectedJourneys); assert.equal(report.mockedWrites.length, expectedJourneys * 5);
assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []);
assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
console.log('PASS:16 controlled discovery journeys,48 axe scans/captures,80 intercepted fixture mutations.');
console.log(`PASS:${report.journeys.length} controlled discovery journeys,${report.screens.length} axe scans/captures,${report.mockedWrites.length} intercepted fixture mutations.`);
} finally {
fs.writeFileSync(path.join(out, 'BROWSER.json'), JSON.stringify({ ...report, limits: ['synthetic provider/API fixtures, not live NAV or backend qualification', 'no new providers/geography or native/security/release acceptance'] }, null, 2));
fs.writeFileSync(path.join(out, process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['synthetic provider/API fixtures, not live NAV or backend qualification', 'no new providers/geography or native/security/release acceptance'] }, null, 2));
await browser.close();
}