Files
ResumeSite/site/test/seo.test.ts
T
cesnimda 033c9ec315 test: vitest unit + playwright e2e suites; fix a11y, contrast, no-JS reveal
- 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>
2026-07-04 06:14:18 +02:00

63 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, it, expect } from 'vitest';
import { alternates, buildJsonLd, absUrl, ogImagePath } from '@lib/seo';
import { PAGE_IDS } from '@i18n/slugMap';
const ORIGIN = 'https://cesnimda.co.uk/';
describe('SEO builders (SEO_SPEC §24)', () => {
it('alternates include en, nb and x-default for every page', () => {
for (const id of PAGE_IDS) {
const alts = alternates(id, ORIGIN);
const langs = alts.map((a) => a.hreflang);
expect(langs).toContain('en');
expect(langs).toContain('nb');
expect(langs).toContain('x-default');
for (const a of alts) expect(a.href.startsWith('https://')).toBe(true);
}
});
it('x-default points at the English URL', () => {
const alts = alternates('projects', ORIGIN);
const xd = alts.find((a) => a.hreflang === 'x-default');
const en = alts.find((a) => a.hreflang === 'en');
expect(xd?.href).toBe(en?.href);
});
it('home JSON-LD is a valid Person graph', () => {
const graph = buildJsonLd('home', 'en', ORIGIN);
const person = graph.find((g) => (g as { '@type': string })['@type'] === 'Person') as Record<
string,
unknown
>;
expect(person).toBeTruthy();
expect(person.name).toBe('Connor Babbington');
expect(person.jobTitle).toBe('Systems Developer');
expect(() => JSON.stringify(graph)).not.toThrow();
});
it('Norwegian home uses the localised job title', () => {
const graph = buildJsonLd('home', 'no', ORIGIN);
const person = graph.find((g) => (g as { '@type': string })['@type'] === 'Person') as Record<
string,
unknown
>;
expect(person.jobTitle).toBe('Systemutvikler');
});
it('case-study JSON-LD carries the project name and author', () => {
const graph = buildJsonLd('jobtrack', 'en', ORIGIN, {
projectName: 'JobTrack',
projectType: 'SoftwareApplication',
});
const work = graph[0] as Record<string, unknown>;
expect(work['@type']).toBe('SoftwareApplication');
expect(work.name).toBe('JobTrack');
expect((work.author as Record<string, unknown>)['@type']).toBe('Person');
});
it('helpers build absolute URLs and OG paths', () => {
expect(absUrl('/projects/', ORIGIN)).toBe('https://cesnimda.co.uk/projects/');
expect(ogImagePath('home', 'no')).toBe('/og/home-no.png');
});
});