033c9ec315
- vitest: dictionary parity, slug-map bijection, content-schema validation, JSON-LD (23) - playwright: both locales, language-switch mapping (incl. no-JS), CV downloads, form happy-path + honeypot, axe a11y on 5 templates x 2 themes (23) - fix: raise ink-faint + light accent to meet WCAG AA 4.5:1 (axe-verified) - fix: gate reveal animations behind html.js so content is visible without JS (progressive enhancement - was hidden at opacity 0); scan reduced-motion path - fix: validate contact form before the anti-bot time-trap (no false success) - chore: ESLint node globals, typed diagram props, resvg fontFiles, prettier pass Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
41 lines
1.7 KiB
TypeScript
41 lines
1.7 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('smoke — both locales render (TECH_SPEC §9.3)', () => {
|
|
test('English home', async ({ page }) => {
|
|
await page.goto('/');
|
|
await expect(page).toHaveTitle(/Systems Developer/);
|
|
await expect(page.locator('h1')).toHaveText('Connor Babbington');
|
|
await expect(page.locator('html')).toHaveAttribute('lang', 'en-GB');
|
|
// decision facts present in the first view (chip)
|
|
await expect(page.getByText('Tønsberg, Norway', { exact: true }).first()).toBeVisible();
|
|
});
|
|
|
|
test('Norwegian home', async ({ page }) => {
|
|
await page.goto('/no/');
|
|
await expect(page).toHaveTitle(/Systemutvikler/);
|
|
await expect(page.locator('html')).toHaveAttribute('lang', 'nb-NO');
|
|
await expect(page.getByText('Gyldig oppholdstillatelse')).toBeVisible();
|
|
});
|
|
|
|
test('hreflang alternates emitted', async ({ page }) => {
|
|
await page.goto('/');
|
|
await expect(page.locator('link[hreflang="en"]')).toHaveCount(1);
|
|
await expect(page.locator('link[hreflang="nb"]')).toHaveCount(1);
|
|
await expect(page.locator('link[hreflang="x-default"]')).toHaveCount(1);
|
|
});
|
|
|
|
test('case study shows architecture and decisions', async ({ page }) => {
|
|
await page.goto('/projects/jobtrack/');
|
|
await expect(page.locator('h1')).toHaveText('JobTrack');
|
|
await expect(page.locator('#architecture svg[role="img"]')).toBeVisible();
|
|
await expect(page.locator('#decisions')).toBeVisible();
|
|
});
|
|
|
|
test('skip link is the first focusable element', async ({ page }) => {
|
|
await page.goto('/');
|
|
await page.keyboard.press('Tab');
|
|
const focused = page.locator(':focus');
|
|
await expect(focused).toHaveText(/Skip to content/);
|
|
});
|
|
});
|