blob: 647da95530ea026c7105dd01e8022a95150010dc [file]
// Every page at phone, tablet and desktop widths, light and dark: no sideways scroll, a
// screenshot of each for the pull request, and an accessibility scan.
import { test, expect, shot, startSession } from './support/fixtures';
import type { Page } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';
const widths = [360, 768, 1280] as const;
type Shown = { name: string; path: (id: string) => string; ready: (page: Page) => Promise<void> };
const pages: Shown[] = [
{ name: 'launch', path: () => '/', ready: async (page) => { await expect(page.locator('#ready li').first()).toBeVisible(); } },
{
name: 'session', path: (id) => `/session.html?id=${id}`,
ready: async (page) => {
await expect(page.locator('.xterm-rows')).toContainText('e2e session: ready');
await expect(page.locator('#s-dest')).toContainText('llmao');
// below 720px the record is a tab of its own; the terminal is what shows first
if (await page.locator('#pane').isVisible()) {
await page.locator('#recent a').first().click();
await expect(page.locator('#emeta')).toBeVisible();
}
},
},
{ name: 'board', path: () => '/board', ready: async (page) => { await expect(page.locator('#lists h2').first()).toBeVisible(); } },
{
name: 'reader', path: () => '/reader',
ready: async (page) => {
await page.getByRole('button', { name: 'dom-e2e', exact: true }).click();
await page.locator('#q').fill('lease');
await page.locator('#hits li button').first().click();
await expect(page.locator('#entry h2')).toBeVisible();
},
},
];
for (const scheme of ['light', 'dark'] as const) {
for (const p of pages) {
test(`${p.name} fits every width in ${scheme}`, async ({ signedIn: page, request }) => {
const id = await startSession(request);
await page.emulateMedia({ colorScheme: scheme });
for (const w of widths) {
await page.setViewportSize({ width: w, height: 900 });
await page.goto(p.path(id));
await p.ready(page);
const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
expect(overflow, `${p.name} scrolls sideways at ${w}px`).toBeLessThanOrEqual(0);
await page.screenshot({ path: shot(`${p.name}-${scheme}-${w}`), fullPage: true });
}
});
test(`${p.name} has no serious accessibility violations in ${scheme}`, async ({ signedIn: page, request }) => {
const id = await startSession(request);
await page.emulateMedia({ colorScheme: scheme });
await page.goto(p.path(id));
await p.ready(page);
const r = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']).analyze();
const serious = r.violations
.filter((v) => v.impact === 'serious' || v.impact === 'critical')
.map((v) => `${v.id}: ${v.nodes.map((n) => `${n.target.join(' ')} (${n.failureSummary ?? ''})`).join('; ')}`);
expect(serious).toEqual([]);
});
}
}
// more contrast, as the system asks for it: the same scan, and a screenshot of each page
for (const p of pages) {
test(`${p.name} with more contrast has no serious accessibility violations`, async ({ signedIn: page, request }) => {
const id = await startSession(request);
await page.emulateMedia({ contrast: 'more' });
await page.setViewportSize({ width: 1280, height: 900 });
await page.goto(p.path(id));
await p.ready(page);
await page.screenshot({ path: shot(`${p.name}-more-1280`), fullPage: true });
const r = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']).analyze();
expect(r.violations.filter((v) => v.impact === 'serious' || v.impact === 'critical').map((v) => v.id)).toEqual([]);
});
}