test(applications): qualify the explicit selection mode

This commit is contained in:
cesnimda
2026-11-10 12:28:50 +01:00
parent 1246994cca
commit 252759f420
90 changed files with 2569 additions and 12 deletions
@@ -11,12 +11,14 @@ const visualMatrix = Boolean(process.env.A3_VISUAL_MATRIX);
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);
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 ? [320, 360, 390, 430, 768, 1024, 1280, 1440, 1920] : [320, 390, 768, 1440];
const configurations = process.env.A3_PILOT ? [[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, 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 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');
fs.mkdirSync(out, { recursive: true });
const report = { screens: [], journeys: [], aliases: [], focusChecks: [], errors: [], unexpectedWrites: [], mockedWrites: [], unavailableReads: [], blockedExternal: [] };
const browser = await chromium.launch();
@@ -29,6 +31,7 @@ try {
await page.addInitScript(({ language, mode }) => { localStorage.setItem('uiLanguage', language); localStorage.setItem('jobtracker.themeMode', mode); }, { language, mode });
const jobs = ['Community nurse', 'Primary teacher', 'Electrical engineer'].map((jobTitle, index) => ({ id: 42 + index, version: 7, jobTitle, company: { id: 1, name: 'Fjord Care' }, companyId: 1, status: 'Saved', location: 'Oslo', countryCode: 'NO', source: 'nav', salary: null, dateApplied: null, savedAt: '2026-10-01T09:00:00Z', deadline: '2026-11-12', followUpAt: null, tags: 'Care coordination', description: 'Recorded source advertisement.', isDeleted: false, needsFollowUp: false, workflowSignal: null }));
if (matchingCountOnly || followupJourney) jobs.splice(1);
if (selectionOnly) jobs[0].workflowSignal = { actionKey: 'package-work', reason: 'Synthetic application preparation', workspaceTab: 'tailored-cv', needsAttention: true, hasPackageGap: true };
let expectedFollowUp = null;
await page.route('**/*', route => {
const req = route.request(), url = new URL(req.url());
@@ -39,7 +42,7 @@ try {
assert.ok(expectedFollowUp); assert.deepEqual(req.postDataJSON(), { followUpAt: expectedFollowUp }); assert.equal(jobs[0].status, 'Waiting'); jobs[0].followUpAt = expectedFollowUp;
report.mockedWrites.push({ width, language, mode, action: 'scheduleFollowUp', recordedDate: expectedFollowUp }); return answer({});
}
if (!matchingCountOnly && req.method() === 'PATCH' && url.pathname === '/api/jobapplications/42/status') {
if (!selectionOnly && !matchingCountOnly && req.method() === 'PATCH' && url.pathname === '/api/jobapplications/42/status') {
const { status } = req.postDataJSON(); assert.equal(status, 'Waiting'); jobs[0].status = status;
report.mockedWrites.push({ width, language, mode, status }); return answer({});
}
@@ -69,9 +72,36 @@ try {
if (!target) await page.evaluate(() => window.scrollTo(0, 0));
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: !target && (width >= 768 || !followupJourney) });
};
await page.goto('http://localhost:4338/jobs');
await page.goto(`http://localhost:4338/jobs${selectionOnly ? '?q=nurse' : ''}`);
const search = page.getByRole('textbox', { name: language === 'en' ? 'Search' : 'Søk', exact: true }); await search.waitFor();
await page.locator('[data-job-row-id="42"], [data-job-card-id="42"]').first().waitFor();
if (selectionOnly) {
const row = page.locator('[data-job-row-id="42"]').first();
const selection = page.getByRole('button', { name: t('jobTableSelectionMode'), exact: true });
const check = row.getByRole('checkbox', { name: t('jobTableSelectJob', { title: jobs[0].jobTitle }), exact: true });
const selectAll = page.getByRole('checkbox', { name: t('jobTableSelectAll'), exact: true });
await expect(selection).toHaveAttribute('aria-pressed', 'false');
await expect(check).toHaveCount(0); await expect(selectAll).toHaveCount(0);
const text = await row.textContent();
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');
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 });
await expect(bulk).toBeVisible(); await scan('selection', bulk);
await bulk.press('Enter');
const dialog = page.getByRole('dialog'); await expect(dialog).toBeVisible();
await dialog.getByRole('button', { name: t('cancel'), exact: true }).press('Enter'); await expect(dialog).toBeHidden();
await expect(check).toBeChecked();
await selection.press('Enter'); await expect(check).toHaveCount(0); await expect(bulk).toHaveCount(0);
await page.getByRole('link', { name: t('jobsBoardView'), exact: true }).press('Enter');
await expect(page.locator('[data-kanban-card-id="42"]')).toBeVisible(); await expect(selection).toHaveCount(0);
await page.getByRole('link', { name: t('jobsTableView'), exact: true }).press('Enter');
await expect(selection).toHaveAttribute('aria-pressed', 'false'); await expect(check).toHaveCount(0);
assert.equal(new URL(page.url()).searchParams.get('q'), 'nurse'); await expect(search).toHaveValue('nurse');
report.journeys.push({ width, language, mode, keyboardSelectionAndCancel: 'PASS', titleBeforeEmployer: 'PASS', boardAndQueryRetained: 'PASS', mutations: 'NOT RUN' }); await context.close(); continue;
}
if (followupJourney) {
await scan('table'); await page.getByRole('link', { name: t('jobsBoardView'), exact: true }).click();
await page.getByRole('button', { name: `${t('jobTableQuickStatus')}: Community nurse`, exact: true }).click(); await page.getByRole('menuitem', { name: t('jobTableSetStatus', { status: t('statusWaiting') }), exact: true }).click();
@@ -159,7 +189,7 @@ try {
}
await context.close();
}
assert.equal(report.screens.length, configurations.length * (followupJourney ? 6 : matchingCountOnly ? 2 : flatWorkspace ? 6 : visualMatrix ? 4 : 3)); assert.equal(report.journeys.length, configurations.length); assert.equal(report.mockedWrites.length, matchingCountOnly ? 0 : configurations.length * (followupJourney ? 2 : 1)); assert.equal(report.aliases.length, visualMatrix && !matchingCountOnly ? 3 : 0);
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.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.`);