style(ui): open career and document surfaces and show single-month activity
This commit is contained in:
@@ -7,12 +7,15 @@ import path from 'node:path';
|
||||
import assert from 'node:assert/strict';
|
||||
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 out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/calendar/browser'); fs.mkdirSync(out, { recursive: true });
|
||||
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 expectedJourneys = widths.length * (process.env.A3_PILOT ? 1 : 4);
|
||||
const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/calendar' : '../../docs/ui-modernisation/evidence/calendar/browser'); fs.mkdirSync(out, { recursive: true });
|
||||
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], reads: [], blockedExternal: [] };
|
||||
const now = new Date(), month = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
|
||||
const browser = await chromium.launch();
|
||||
try {
|
||||
for (const width of (process.env.A3_PILOT ? [320] : [320, 390, 768, 1440])) for (const language of (process.env.A3_PILOT ? ['en'] : ['en', 'nb'])) for (const mode of (process.env.A3_PILOT ? ['light'] : ['light', 'dark'])) {
|
||||
for (const width of widths) for (const language of (process.env.A3_PILOT ? ['en'] : ['en', 'nb'])) for (const mode of (process.env.A3_PILOT ? ['light'] : ['light', 'dark'])) {
|
||||
console.log(`Checking ${width}/${language}/${mode}`);
|
||||
const t = (key, params = {}) => translations[language][key].replace(/\{(\w+)\}/g, (_, name) => String(params[name] ?? `{${name}}`));
|
||||
const context = await browser.newContext({ viewport: { width, height: 1000 }, reducedMotion: 'reduce' }); const page = await context.newPage();
|
||||
@@ -39,7 +42,7 @@ try {
|
||||
const scan = async state => {
|
||||
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false, state);
|
||||
const axe = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze(); report.screens.push({ width, language, mode, state, violations: axe.violations }); assert.deepEqual(axe.violations, []);
|
||||
await page.evaluate(() => window.scrollTo(0, 0)); await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: true });
|
||||
await page.evaluate(() => window.scrollTo(0, 0)); await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 });
|
||||
};
|
||||
await page.goto('http://localhost:4338/reminders');
|
||||
const calendar = page.getByRole('region', { name: t('calendarAgendaTitle'), exact: true }); await calendar.getByRole('link', { name: /Electrical engineer/ }).waitFor();
|
||||
@@ -61,6 +64,7 @@ try {
|
||||
assert.equal((await page.locator('main').innerText()).includes('Invalid Date'), false); await scan('linked-application');
|
||||
report.journeys.push({ width, language, mode, agendaMonthSelectionPersistedPreferenceBoundedMonthNavigationLinkedDeadline: 'PASS' }); await context.close();
|
||||
}
|
||||
assert.equal(report.journeys.length, expectedJourneys); assert.equal(report.screens.length, expectedJourneys * 3);
|
||||
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} calendar journeys,${report.screens.length} axe scans/captures,zero writes.`);
|
||||
} finally { fs.writeFileSync(path.join(out, process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['Controlled API fixtures, not a live backend/provider or reminder delivery.', 'Date-level recorded deadline/follow-up display; no fabricated interview appointments or source timezone reconstruction.', 'No native-device, physical rendering, final security or release qualification.'] }, null, 2)); await browser.close(); }
|
||||
|
||||
@@ -7,12 +7,13 @@ import fs from 'node:fs';
|
||||
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 out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/career/browser');
|
||||
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
|
||||
const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/career' : '../../docs/ui-modernisation/evidence/career/browser');
|
||||
fs.mkdirSync(out, { recursive: true });
|
||||
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], renderReads: 0, unavailableReads: [], blockedExternal: [] };
|
||||
const browser = await chromium.launch();
|
||||
try {
|
||||
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? [[320, 'en', 'light']] : [320, 390, 768, 1440].flatMap(width => ['en', 'nb'].flatMap(language => ['light', 'dark'].map(mode => [width, language, mode])));
|
||||
const configurations = process.env.A3_BOUNDARY ? [320, 390, 768, 1000, 1001, 1440].map(width => [width, 'en', 'light']) : process.env.A3_PILOT ? [[320, 'en', 'light']] : (visualMatrix ? [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]; };
|
||||
@@ -66,11 +67,13 @@ try {
|
||||
if (Object.hasOwn(fixtures, p)) return answer(fixtures[p]);
|
||||
report.unavailableReads.push(p); return route.fulfill({ status: 404, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
const scan = async state => {
|
||||
const scan = async (state, target) => {
|
||||
if (target) await target.evaluate(node => node.scrollIntoView({ block: 'center', behavior: 'instant' }));
|
||||
else await page.evaluate(() => window.scrollTo(0, 0));
|
||||
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false, `overflow:${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, [], `${state} accessibility`);
|
||||
await page.evaluate(() => window.scrollTo(0, 0)); await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: true });
|
||||
report.screens.push({ width, language, mode, state, capture: target ? 'targeted viewport' : width >= 768 ? 'full page at top' : 'viewport at top', violations: result.violations }); assert.deepEqual(result.violations, [], `${state} accessibility`);
|
||||
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 && !target });
|
||||
};
|
||||
const careerSection = async key => {
|
||||
if (width >= 600) await page.getByRole('tab', { name: t(key), exact: true }).click();
|
||||
@@ -81,7 +84,7 @@ try {
|
||||
for (const key of ['contact', 'summary', 'skills', 'interests', 'awards', 'publications', 'organisations', 'references', 'languages', 'jobs', 'education', 'certifications', 'projects', 'otherSections']) {
|
||||
await page.locator(`[data-edit-career-section="${key}"]`).press('Enter');
|
||||
await expect.poll(() => page.locator(`#career-section-${key}`).evaluate(node => node.contains(document.activeElement))).toBe(true);
|
||||
if (process.env.A3_BOUNDARY) await expect.poll(async () => page.evaluate(() => {
|
||||
if (process.env.A3_BOUNDARY || visualMatrix) await expect.poll(async () => page.evaluate(() => {
|
||||
const active = document.activeElement, rect = active.getBoundingClientRect();
|
||||
const x = Math.min(innerWidth - 1, Math.max(0, rect.x + rect.width / 2)), y = Math.min(innerHeight - 1, Math.max(0, rect.y + rect.height / 2));
|
||||
const hit = document.elementFromPoint(x, y);
|
||||
@@ -91,10 +94,10 @@ try {
|
||||
}
|
||||
await page.locator('[data-edit-career-section="projects"]').click();
|
||||
const projectName = page.locator('#career-section-projects input').first(); await projectName.fill('Updated community project');
|
||||
await page.getByRole('button', { name: t('profileSaveChanges'), exact: true }).click(); await expect.poll(() => career.revision).toBe(8); await expect(projectName).toBeEnabled(); await scan('profile');
|
||||
await page.getByRole('button', { name: t('profileSaveChanges'), exact: true }).click(); await expect.poll(() => career.revision).toBe(8); await expect(projectName).toBeEnabled(); await scan('profile', projectName);
|
||||
await careerSection('careerWorkspaceImportTab');
|
||||
const run = page.locator('#career-import-run-41'); await expect(run).toContainText('A2'); await expect(run).toContainText('B1');
|
||||
await run.getByRole('checkbox').check(); await expect(run.getByRole('checkbox')).toBeChecked(); await scan('import-review');
|
||||
await run.getByRole('checkbox').check(); await expect(run.getByRole('checkbox')).toBeChecked(); await scan('import-review', run);
|
||||
assert.equal(report.mockedWrites.filter(row => row.width === width && row.language === language && row.mode === mode).length, 1);
|
||||
await page.goto('http://localhost:4338/career/builder');
|
||||
const cvCard = page.getByRole('link', { name: t('cvDashboardOpenNamed').replace('{name}', 'Teacher CV'), exact: true });
|
||||
@@ -107,7 +110,7 @@ try {
|
||||
assert.ok(width > 1000 ? right.x >= left.x + left.width - 2 : right.y >= left.y + left.height - 2, 'CV pane geometry');
|
||||
}
|
||||
const cvName = page.getByRole('textbox', { name: t('cvEditorName'), exact: true }); await cvName.fill('Updated teacher CV');
|
||||
await expect.poll(() => variant.name, { timeout: 15000 }).toBe('Updated teacher CV'); await scan('cv-editor');
|
||||
await expect.poll(() => variant.name, { timeout: 15000 }).toBe('Updated teacher CV'); await scan('cv-editor', cvName);
|
||||
await page.goto('http://localhost:4338/jobs/42?section=application&sub=letter');
|
||||
const text = page.getByRole('textbox', { name: t('jobDetailsCoverLetter'), exact: true }); await expect(text).toBeEnabled();
|
||||
await text.fill('Dear team\n\nUpdated teaching experience.');
|
||||
@@ -117,7 +120,7 @@ try {
|
||||
await expect(letterPreview).toContainText('Updated teaching experience.'); const panes = page.locator('[data-letter-studio-layout] > div'); const left = await panes.nth(0).boundingBox(), right = await panes.nth(1).boundingBox();
|
||||
assert.ok(width > 1000 ? right.x >= left.x + left.width - 2 : right.y >= left.y + left.height - 2, 'Letter pane geometry');
|
||||
}
|
||||
await page.getByRole('button', { name: t('save'), exact: true }).click(); await expect.poll(() => letter.revision).toBe(8); await expect(text).toBeEnabled(); await scan('letter');
|
||||
await page.getByRole('button', { name: t('save'), exact: true }).click(); await expect.poll(() => letter.revision).toBe(8); await expect(text).toBeEnabled(); await scan('letter', text);
|
||||
report.journeys.push({ width, language, mode, all14KeyboardEditTargets: 'PASS', canonicalSaveStableIds: 'PASS', legacyImportComparisonSelectionNoApply: 'PASS', libraryKeyboardOpen: 'PASS', cvResponsiveRename: 'PASS', letterResponsiveManualSave: 'PASS' });
|
||||
await context.close();
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@ import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
const visualMatrix = process.env.A3_VISUAL_MATRIX === '1';
|
||||
const markerOnly = process.env.A3_ACTIVITY_MARKER === '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');
|
||||
const out = path.resolve(import.meta.dirname, markerOnly ? '../../docs/ui-modernisation/visual-correction/evidence/activity-markers' : 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();
|
||||
@@ -68,6 +69,18 @@ try {
|
||||
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;
|
||||
});
|
||||
if (markerOnly) {
|
||||
const activity = page.locator('[data-dashboard-widget=activity]');
|
||||
await page.waitForFunction(() => document.querySelectorAll('[data-dashboard-widget=activity] svg circle').length === 2);
|
||||
const markers = activity.locator('svg circle');
|
||||
assert.equal(await markers.nth(0).getAttribute('cy'), '20'); assert.equal(await markers.nth(1).getAttribute('cy'), '140');
|
||||
await activity.scrollIntoViewIfNeeded();
|
||||
const panel = activity.getByRole('group'); if (await panel.count()) await panel.evaluate(node => { node.scrollTop = 0; });
|
||||
const scan = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze();
|
||||
report.screens.push({ width, language, mode, state: 'single-month-markers', violations: scan.violations }); assert.deepEqual(scan.violations, []);
|
||||
await page.screenshot({ path: path.join(out, `single-month-${language}-${mode}-${width}.png`) });
|
||||
report.journeys.push({ width, language, mode, recordedSingleMonthMarkersSharedScale: 'PASS' }); await context.close(); continue;
|
||||
}
|
||||
const scan = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze();
|
||||
report.screens.push({ width, language, mode, violations: scan.violations }); assert.deepEqual(scan.violations, []);
|
||||
await page.screenshot({ path: path.join(out, `dashboard-${language}-${mode}-${width}.png`), fullPage: true });
|
||||
@@ -100,9 +113,9 @@ 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, expectedJourneys);
|
||||
assert.equal(report.mockedWrites.length, markerOnly ? 0 : expectedJourneys);
|
||||
assert.equal(report.journeys.length, expectedJourneys);
|
||||
assert.equal(report.screens.length, expectedJourneys * 2);
|
||||
assert.equal(report.screens.length, expectedJourneys * (markerOnly ? 1 : 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, 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));
|
||||
|
||||
@@ -7,11 +7,14 @@ import path from 'node:path';
|
||||
import assert from 'node:assert/strict';
|
||||
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 out = path.resolve(import.meta.dirname, '../../docs/ui-modernisation/evidence/documents-inbox/browser'); fs.mkdirSync(out, { recursive: true });
|
||||
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 expectedJourneys = widths.length * (process.env.A3_PILOT ? 1 : 4);
|
||||
const out = path.resolve(import.meta.dirname, visualMatrix ? '../../docs/ui-modernisation/visual-correction/evidence/documents-inbox' : '../../docs/ui-modernisation/evidence/documents-inbox/browser'); fs.mkdirSync(out, { recursive: true });
|
||||
const report = { screens: [], journeys: [], errors: [], unexpectedWrites: [], mockedWrites: [], unavailableReads: [], blockedExternal: [] };
|
||||
const browser = await chromium.launch();
|
||||
try {
|
||||
for (const width of (process.env.A3_PILOT ? [320] : [320, 390, 768, 1440])) for (const language of (process.env.A3_PILOT ? ['en'] : ['en', 'nb'])) for (const mode of (process.env.A3_PILOT ? ['light'] : ['light', 'dark'])) {
|
||||
for (const width of widths) for (const language of (process.env.A3_PILOT ? ['en'] : ['en', 'nb'])) for (const mode of (process.env.A3_PILOT ? ['light'] : ['light', 'dark'])) {
|
||||
console.log(`Checking ${width}/${language}/${mode}`);
|
||||
const t = key => { assert.ok(translations[language][key], key); return translations[language][key]; };
|
||||
const context = await browser.newContext({ viewport: { width, height: 1000 }, reducedMotion: 'reduce', acceptDownloads: true }); const page = await context.newPage();
|
||||
@@ -46,10 +49,12 @@ try {
|
||||
};
|
||||
if (Object.hasOwn(fixtures, p)) return answer(fixtures[p]); report.unavailableReads.push(p); return route.fulfill({ status: 404, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
const scan = async state => {
|
||||
const scan = async (state, target) => {
|
||||
if (target) await target.evaluate(node => node.scrollIntoView({ block: 'center', behavior: 'instant' }));
|
||||
else await page.evaluate(() => window.scrollTo(0, 0));
|
||||
assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false, state);
|
||||
const axe = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze(); report.screens.push({ width, language, mode, state, violations: axe.violations }); assert.deepEqual(axe.violations, []);
|
||||
await page.evaluate(() => window.scrollTo(0, 0)); await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: true });
|
||||
const axe = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze(); report.screens.push({ width, language, mode, state, capture: target ? 'targeted viewport' : width >= 768 ? 'full page at top' : 'viewport at top', violations: axe.violations }); assert.deepEqual(axe.violations, []);
|
||||
await page.screenshot({ path: path.join(out, `${state}-${language}-${mode}-${width}.png`), fullPage: width >= 768 && !target });
|
||||
};
|
||||
await page.goto('http://localhost:4338/documents');
|
||||
const docs = page.getByRole('region', { name: t('documentsYourDocuments'), exact: true }); await docs.getByText(document.name, { exact: true }).waitFor(); await scan('documents');
|
||||
@@ -57,18 +62,18 @@ try {
|
||||
await docs.getByRole('button', { name: t('documentsReturnFilters'), exact: true }).click(); const search = page.getByRole('textbox', { name: t('documentsSearch'), exact: true }); await expect(search).toBeFocused(); assert.equal(documentReads, reads);
|
||||
await search.fill('certificate'); await expect(docs.getByText(cv.name, { exact: true })).toHaveCount(0); await docs.getByText(document.name, { exact: true }).waitFor();
|
||||
const download = page.waitForEvent('download'); await docs.getByRole('button', { name: t('documentsDownloadAttachment'), exact: true }).click(); const file = await download; assert.equal(file.suggestedFilename(), document.name); assert.equal(fs.readFileSync(await file.path(), 'utf8'), 'Controlled certificate fixture');
|
||||
assert.equal(await docs.getByRole('link', { name: t('documentsOpenSource'), exact: true }).getAttribute('href'), document.sourceHref); assert.equal(await docs.locator('time').getAttribute('datetime'), document.recordedAt); await scan('document-filtered');
|
||||
assert.equal(await docs.getByRole('link', { name: t('documentsOpenSource'), exact: true }).getAttribute('href'), document.sourceHref); assert.equal(await docs.locator('time').getAttribute('datetime'), document.recordedAt); await scan('document-filtered', docs.getByText(document.name, { exact: true }));
|
||||
await page.goto('http://localhost:4338/correspondence'); const messages = page.getByRole('region', { name: t('emailInboxLinkedMessages'), exact: true }); await messages.getByText(mail.subject, { exact: true }).waitFor(); await scan('inbox');
|
||||
const initialMailReads = mailReads; await page.getByRole('button', { name: t('emailInboxJumpMessages'), exact: true }).press('Enter'); await expect(messages).toBeFocused(); await messages.getByRole('button', { name: t('emailInboxReturnFilters'), exact: true }).click(); await expect(page.getByRole('textbox', { name: t('correspondenceSearch'), exact: true })).toBeFocused(); assert.equal(mailReads, initialMailReads);
|
||||
await messages.getByRole('button', { name: t('emailInboxViewMessage'), exact: true }).click(); await messages.getByText('Please choose an interview time. <script>inert text</script>', { exact: true }).waitFor(); await scan('message');
|
||||
await messages.getByRole('button', { name: t('emailInboxViewMessage'), exact: true }).click(); const messageBody = messages.getByText('Please choose an interview time. <script>inert text</script>', { exact: true }); await messageBody.waitFor(); await scan('message', messageBody);
|
||||
await messages.getByRole('button', { name: t('emailInboxReply'), exact: true }).click(); const compose = page.getByRole('region', { name: t('emailInboxDraftTitle'), exact: true });
|
||||
await compose.getByRole('textbox', { name: t('emailInboxRecipient'), exact: true }).fill('recruiter@example.test'); await compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true }).fill('Thank you. Please confirm the available interview times.');
|
||||
await compose.getByRole('button', { name: t('emailInboxSaveDraft'), exact: true }).click(); await expect.poll(() => draft?.revision).toBe(4);
|
||||
await compose.getByRole('button', { name: t('emailInboxReviewSend'), exact: true }).click(); const dialog = page.getByRole('dialog', { name: t('emailInboxConfirmSendTitle'), exact: true }); await dialog.waitFor(); assert.equal(sends, 0); await scan('send-confirmation');
|
||||
await compose.getByRole('button', { name: t('emailInboxReviewSend'), exact: true }).click(); const dialog = page.getByRole('dialog', { name: t('emailInboxConfirmSendTitle'), exact: true }); await dialog.waitFor(); assert.equal(sends, 0); await scan('send-confirmation', dialog);
|
||||
await dialog.getByRole('button', { name: t('emailInboxSendEmail'), exact: true }).click(); await compose.getByText(t('emailInboxDeliveryUncertain'), { exact: true }).waitFor(); await expect(compose.getByRole('button', { name: t('emailInboxReviewSend'), exact: true })).toBeDisabled();
|
||||
assert.equal(sends, 1); await expect(compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true })).toHaveValue(draft.bodyText); await scan('uncertain-send');
|
||||
assert.equal(sends, 1); await expect(compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true })).toHaveValue(draft.bodyText); await scan('uncertain-send', compose.getByRole('textbox', { name: t('emailInboxMessage'), exact: true }));
|
||||
report.journeys.push({ width, language, mode, documentFilterFocusDownloadSource: 'PASS', inboxFocusPlainTextReplySaveExplicitConfirmUncertainNoRetry: 'PASS' }); await context.close();
|
||||
}
|
||||
assert.equal(report.screens.length, report.journeys.length * 6); assert.equal(report.mockedWrites.length, report.journeys.length * 2); assert.deepEqual(report.errors, []); assert.deepEqual(report.unexpectedWrites, []); assert.ok(report.blockedExternal.every(origin => origin === 'https://fonts.googleapis.com'));
|
||||
assert.equal(report.journeys.length, expectedJourneys); assert.equal(report.screens.length, report.journeys.length * 6); assert.equal(report.mockedWrites.length, report.journeys.length * 2); 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} document/mail journeys,${report.screens.length} axe scans/captures,${report.mockedWrites.length} fixture-only save/send requests.`);
|
||||
} finally { fs.writeFileSync(path.join(out, process.env.A3_PILOT ? 'PILOT.json' : 'BROWSER.json'), JSON.stringify({ ...report, limits: ['Synthetic metadata/binary/mail/provider fixtures; not live storage, mailbox, OAuth or delivery.', 'Browser covers draft save, explicit confirmation and controlled uncertain outcome only; other recovery/conflict paths remain targeted tests.', 'No real sending, native device, final integrated security or release acceptance.'] }, null, 2)); await browser.close(); }
|
||||
|
||||
Reference in New Issue
Block a user