test(a3): qualify compact application actions across responsive states

This commit is contained in:
cesnimda
2026-11-10 23:11:24 +01:00
parent bfbfaeb903
commit 9c9fe48d5f
130 changed files with 4298 additions and 8 deletions
@@ -12,13 +12,15 @@ const flatWorkspace = Boolean(process.env.A3_FLAT_WORKSPACE);
const matchingCountOnly = Boolean(process.env.A3_MATCHING_COUNT);
const followupJourney = Boolean(process.env.A3_FOLLOWUP_JOURNEY);
const selectionOnly = Boolean(process.env.A3_APPLICATION_SELECTION);
const rowActions = Boolean(process.env.A3_APPLICATION_ACTIONS);
assert.ok(!rowActions || selectionOnly, 'Row action checks extend the selection journey.');
assert.ok(!selectionOnly || !(followupJourney || matchingCountOnly || flatWorkspace || visualMatrix), 'Selection is a focused independent scope.');
assert.ok(!followupJourney || !(matchingCountOnly || flatWorkspace || visualMatrix), 'Follow-up journey is a representative independent scope.');
assert.ok(!matchingCountOnly || !flatWorkspace, 'Count presentation does not repeat workspace qualification.');
assert.ok(!flatWorkspace || visualMatrix, 'Flat workspace qualification uses the visual matrix.');
const widths = followupJourney ? [390, 1440] : visualMatrix || matchingCountOnly || selectionOnly ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440];
const configurations = process.env.A3_PILOT ? (selectionOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[followupJourney ? 390 : 320, 'en', 'light']]) : widths.flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
const out = path.resolve(import.meta.dirname, selectionOnly ? '../../docs/ui-modernisation/visual-correction/evidence/applications-selection' : followupJourney ? '../../docs/ui-modernisation/visual-correction/evidence/followup-journey' : matchingCountOnly ? '../../docs/ui-modernisation/visual-correction/evidence/matching-count' : flatWorkspace ? '../../docs/ui-modernisation/visual-correction/evidence/applications-flat' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/applications' : '../../docs/ui-modernisation/evidence/applications/browser');
const configurations = process.env.A3_PILOT ? (rowActions ? [[320, 'en', 'light'], [768, 'en', 'light'], [1024, 'en', 'dark'], [1440, 'en', 'light']] : selectionOnly ? [[320, 'en', 'light'], [1440, 'en', 'light']] : [[followupJourney ? 390 : 320, 'en', 'light']]) : widths.flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
const out = path.resolve(import.meta.dirname, rowActions ? '../../docs/ui-modernisation/visual-correction/evidence/application-actions' : selectionOnly ? '../../docs/ui-modernisation/visual-correction/evidence/applications-selection' : followupJourney ? '../../docs/ui-modernisation/visual-correction/evidence/followup-journey' : matchingCountOnly ? '../../docs/ui-modernisation/visual-correction/evidence/matching-count' : flatWorkspace ? '../../docs/ui-modernisation/visual-correction/evidence/applications-flat' : visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/applications' : '../../docs/ui-modernisation/evidence/applications/browser');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], aliases: [], focusChecks: [], errors: [], unexpectedWrites: [], mockedWrites: [], unavailableReads: [], blockedExternal: [] };
const browser = await chromium.launch();
@@ -66,7 +68,11 @@ try {
});
const scan = async (state, target) => {
if (target) await target.evaluate(el => el.scrollIntoView({ block: 'center', behavior: 'instant' }));
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false);
if (await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1)) {
console.error('Overflow geometry', state, await page.evaluate(() => ({ width: innerWidth, scrollWidth: document.documentElement.scrollWidth, scrollX, bodyWidth: document.body.scrollWidth })));
await page.screenshot({ path: path.join(out, `FAILED-${state}-${language}-${mode}-${width}.png`) });
}
assert.ok(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth + 1), `Page overflow in ${state}`);
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, []);
if (!target) await page.evaluate(() => window.scrollTo(0, 0));
@@ -86,6 +92,32 @@ try {
assert.ok(text.includes(jobs[0].jobTitle) && text.includes(jobs[0].company.name) && text.indexOf(jobs[0].jobTitle) < text.indexOf(jobs[0].company.name));
await expect(row.getByText(t('jobTablePackageWork'), { exact: true })).toBeVisible();
await scan('ordinary');
if (rowActions) {
const trigger = row.getByRole('button', { name: `${t('jobTableActions')}: ${jobs[0].jobTitle}`, exact: true });
await trigger.press('Enter');
const menu = page.getByRole('menu', { name: t('jobTableActions'), exact: true });
await expect(menu.getByRole('menuitem', { name: t('jobTableEdit'), exact: true })).toBeVisible();
await expect(menu.getByRole('menuitem', { name: t('jobTableSetStatus', { status: t('statusWaiting') }), exact: true })).toBeVisible();
await scan('row-actions', menu);
await page.keyboard.press('Escape');
await expect(menu).toBeHidden();
await expect(trigger).toBeFocused();
await trigger.press('Enter');
await menu.getByRole('menuitem', { name: t('jobTableSoftDelete'), exact: true }).press('Enter');
const confirmation = page.getByRole('dialog');
await confirmation.getByRole('button', { name: t('cancel'), exact: true }).press('Enter');
await expect(confirmation).toBeHidden();
await expect(trigger).toBeFocused();
assert.equal(new URL(page.url()).pathname, '/jobs');
if (width === 320 || width === 768) {
await trigger.press('Enter');
await expect(menu).toBeVisible();
await page.setViewportSize({ width: width === 320 ? 768 : 767, height: 1000 });
await expect(menu).toBeHidden();
await page.setViewportSize({ width, height: 1000 });
await expect(trigger).toHaveAttribute('aria-expanded', 'false');
}
}
await selection.press('Enter'); await expect(selection).toHaveAttribute('aria-pressed', 'true');
await expect(selectAll).toBeVisible(); await check.press('Space'); await expect(check).toBeChecked();
const bulk = page.getByRole('button', { name: t('jobTableDeleteSelected'), exact: true });
@@ -189,7 +221,7 @@ try {
}
await context.close();
}
assert.equal(report.screens.length, configurations.length * (followupJourney ? 6 : matchingCountOnly || selectionOnly ? 2 : flatWorkspace ? 6 : visualMatrix ? 4 : 3)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, matchingCountOnly || selectionOnly ? 0 : configurations.length * (followupJourney ? 2 : 1)); assert.equal(report.aliases.length, visualMatrix && !matchingCountOnly ? 3 : 0);
assert.equal(report.screens.length, configurations.length * (followupJourney ? 6 : rowActions ? 3 : matchingCountOnly || selectionOnly ? 2 : flatWorkspace ? 6 : visualMatrix ? 4 : 3)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, matchingCountOnly || selectionOnly ? 0 : configurations.length * (followupJourney ? 2 : 1)); assert.equal(report.aliases.length, visualMatrix && !matchingCountOnly ? 3 : 0);
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;${report.mockedWrites.length} mocked mutation requests.`);