feat(timeline): add EventPill for derived + curated event pills
Centered axis pill: derived life-events (* Geburt / † Tod / ⚭ Heirat) and curated PERSONAL events (★, mint border) via getAccentConfig. Glyph wrapped aria-hidden + sr-only label (REQ-018). Edit affordance only for a curated event with eventId, never derived/null (REQ-008). REQ-007. Refs #779 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
90
frontend/src/lib/timeline/EventPill.svelte.spec.ts
Normal file
90
frontend/src/lib/timeline/EventPill.svelte.spec.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import EventPill from './EventPill.svelte';
|
||||
import { makeEntry } from './test-factories';
|
||||
|
||||
afterEach(() => cleanup());
|
||||
|
||||
const EVENT_ID = '33333333-3333-3333-3333-333333333333';
|
||||
|
||||
function derived(derivedType: 'BIRTH' | 'DEATH' | 'MARRIAGE', title: string) {
|
||||
return makeEntry({
|
||||
kind: 'EVENT',
|
||||
derived: true,
|
||||
derivedType,
|
||||
title,
|
||||
senderName: '',
|
||||
receiverName: '',
|
||||
precision: 'YEAR',
|
||||
eventDate: '1914-01-01',
|
||||
documentId: undefined
|
||||
});
|
||||
}
|
||||
|
||||
describe('EventPill', () => {
|
||||
it('renders a derived marriage as ⚭ + "Heirat" + title (REQ-007)', () => {
|
||||
render(EventPill, { entry: derived('MARRIAGE', 'Heirat: Karl & Elfriede') });
|
||||
expect(document.body.textContent).toContain('⚭');
|
||||
expect(document.body.textContent).toContain('Heirat');
|
||||
expect(document.body.textContent).toContain('Heirat: Karl & Elfriede');
|
||||
});
|
||||
|
||||
it('renders a derived birth as * + "Geburt" (REQ-007)', () => {
|
||||
render(EventPill, { entry: derived('BIRTH', 'Geburt: Hans') });
|
||||
expect(document.body.textContent).toContain('*');
|
||||
expect(document.body.textContent).toContain('Geburt');
|
||||
});
|
||||
|
||||
it('renders a derived death as † + "Tod" (REQ-007)', () => {
|
||||
render(EventPill, { entry: derived('DEATH', 'Tod: Karl') });
|
||||
expect(document.body.textContent).toContain('†');
|
||||
expect(document.body.textContent).toContain('Tod');
|
||||
});
|
||||
|
||||
it('wraps the glyph aria-hidden with an sr-only label sibling (REQ-018)', () => {
|
||||
render(EventPill, { entry: derived('BIRTH', 'Geburt: Hans') });
|
||||
const hidden = document.querySelector('[aria-hidden="true"]');
|
||||
expect(hidden?.textContent).toBe('*');
|
||||
const srOnly = document.querySelector('.sr-only');
|
||||
expect(srOnly?.textContent).toBe('Geburt');
|
||||
});
|
||||
|
||||
it('shows an edit affordance for a curated PERSONAL event with an eventId (REQ-008)', () => {
|
||||
render(EventPill, {
|
||||
entry: makeEntry({
|
||||
kind: 'EVENT',
|
||||
derived: false,
|
||||
type: 'PERSONAL',
|
||||
eventId: EVENT_ID,
|
||||
title: 'Auswanderung',
|
||||
senderName: '',
|
||||
receiverName: '',
|
||||
documentId: undefined
|
||||
})
|
||||
});
|
||||
const edit = document.querySelector('[data-testid="event-edit"]') as HTMLAnchorElement | null;
|
||||
expect(edit).not.toBeNull();
|
||||
expect(edit?.getAttribute('href')).toContain(EVENT_ID);
|
||||
});
|
||||
|
||||
it('shows no edit affordance when eventId is null (REQ-008)', () => {
|
||||
render(EventPill, {
|
||||
entry: makeEntry({
|
||||
kind: 'EVENT',
|
||||
derived: false,
|
||||
type: 'PERSONAL',
|
||||
eventId: undefined,
|
||||
title: 'Auswanderung',
|
||||
senderName: '',
|
||||
receiverName: '',
|
||||
documentId: undefined
|
||||
})
|
||||
});
|
||||
expect(document.querySelector('[data-testid="event-edit"]')).toBeNull();
|
||||
});
|
||||
|
||||
it('shows no edit affordance for a derived event (REQ-008)', () => {
|
||||
render(EventPill, { entry: derived('MARRIAGE', 'Heirat') });
|
||||
expect(document.querySelector('[data-testid="event-edit"]')).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user