feat(frontend): add accessible DocumentDate render component
Wraps formatDocumentDate with the accessible presentation layer: a non-color
UNKNOWN cue (decorative calendar-with-question icon, aria-hidden, since the
visible "Datum unbekannt" text is the textual cue — WCAG 1.4.1), and the
verbatim meta_date_raw shown as a VISIBLE secondary "Originaltext: …" line for
UNKNOWN/SEASON/APPROX (WCAG 1.4.13, not tooltip-only). raw is rendered via
Svelte default escaping, never {@html} (CWE-79); a component test asserts an
angle-bracket raw value stays inert. Browser test is CI-only.
Refs #666
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
35
frontend/src/lib/document/DocumentDate.svelte.test.ts
Normal file
35
frontend/src/lib/document/DocumentDate.svelte.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import DocumentDate from './DocumentDate.svelte';
|
||||
|
||||
// Browser-project (Playwright) tests — CI only.
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('DocumentDate', () => {
|
||||
it('renders a DAY date as a full long date', async () => {
|
||||
render(DocumentDate, { props: { iso: '1943-12-24', precision: 'DAY' } });
|
||||
await expect.element(page.getByText('24. Dezember 1943')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders MONTH precision as month + year, never a day', async () => {
|
||||
render(DocumentDate, { props: { iso: '1916-06-01', precision: 'MONTH', raw: 'Juni 1916' } });
|
||||
await expect.element(page.getByText('Juni 1916')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the verbatim raw cell as a visible secondary line for UNKNOWN (not tooltip-only)', async () => {
|
||||
render(DocumentDate, { props: { iso: null, precision: 'UNKNOWN', raw: 'Sommer?' } });
|
||||
// Real, visible text — not hidden behind a title attribute.
|
||||
await expect.element(page.getByText('Datum unbekannt')).toBeInTheDocument();
|
||||
await expect.element(page.getByText(/Sommer\?/)).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders a malicious raw value as inert escaped text (no element injected)', async () => {
|
||||
const malicious = '<img src=x onerror="alert(1)">';
|
||||
render(DocumentDate, { props: { iso: null, precision: 'UNKNOWN', raw: malicious } });
|
||||
// The payload appears as literal text, and no <img> is created in the DOM.
|
||||
await expect.element(page.getByText(/<img/)).toBeInTheDocument();
|
||||
expect(document.querySelector('img')).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user