Files
familienarchiv/frontend/e2e/zeitstrahl-note.spec.ts
Marcel 82979be705
Some checks failed
CI / Unit & Component Tests (pull_request) Failing after 3m58s
CI / OCR Service Tests (pull_request) Successful in 25s
CI / Backend Unit Tests (pull_request) Successful in 6m21s
CI / fail2ban Regex (pull_request) Failing after 46s
CI / Semgrep Security Scan (pull_request) Successful in 24s
CI / Compose Bucket Idempotency (pull_request) Successful in 1m10s
SDD Gate / RTM Check (pull_request) Successful in 15s
SDD Gate / Contract Validate (pull_request) Successful in 23s
SDD Gate / Constitution Impact (pull_request) Successful in 20s
test(timeline): add Playwright e2e + RTM rows for event note (#844)
zeitstrahl-note.spec.ts seeds PERSONAL and HISTORICAL events with
descriptions via API and asserts the note appears in DOM (REQ-001, REQ-004).
RTM rows REQ-001–REQ-008 for #844 all marked Done.

Closes #844
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 15:08:25 +02:00

78 lines
2.7 KiB
TypeScript

import { test, expect, type APIRequestContext } from '@playwright/test';
/**
* Curator-note display on /zeitstrahl (#844) — validates that a description saved
* against a curated timeline event surfaces in the DOM under that event's title.
* Covers REQ-001 (description flows from backend) and REQ-004 (rendered below title).
*/
const stamp = () => new Date().toISOString().replace(/[^0-9]/g, '');
async function createEvent(
request: APIRequestContext,
type: 'PERSONAL' | 'HISTORICAL',
title: string,
description: string
): Promise<string> {
const res = await request.post('/api/timeline/events', {
data: {
title,
type,
eventDate: '1918-11-11',
precision: 'DAY',
description
}
});
if (!res.ok()) throw new Error(`create event failed: ${res.status()} ${await res.text()}`);
return (await res.json()).id as string;
}
async function deleteEvent(request: APIRequestContext, id: string): Promise<void> {
await request.delete(`/api/timeline/events/${id}`);
}
test.describe('Zeitstrahl event note (#844)', () => {
let personalEventId: string;
let historicalEventId: string;
const personalTitle = `E2E Persönlich ${stamp()}`;
const historicalTitle = `E2E Historisch ${stamp()}`;
const personalNote = 'Persönliche Notiz für diesen Moment.';
const historicalNote = 'Historischer Kontext für dieses Ereignis.';
test.beforeAll(async ({ request }) => {
personalEventId = await createEvent(request, 'PERSONAL', personalTitle, personalNote);
historicalEventId = await createEvent(request, 'HISTORICAL', historicalTitle, historicalNote);
});
test.afterAll(async ({ request }) => {
if (personalEventId) await deleteEvent(request, personalEventId);
if (historicalEventId) await deleteEvent(request, historicalEventId);
});
test('PERSONAL curated event note appears below its title on /zeitstrahl (REQ-001, REQ-004)', async ({
page
}) => {
await page.goto('/zeitstrahl');
const personalEntry = page.locator('li').filter({ hasText: personalTitle }).first();
await expect(personalEntry).toBeVisible({ timeout: 10000 });
const note = personalEntry.locator('[data-testid="event-note"]');
await expect(note).toBeVisible();
await expect(note).toContainText(personalNote);
});
test('HISTORICAL curated event note appears below its title on /zeitstrahl (REQ-001, REQ-004)', async ({
page
}) => {
await page.goto('/zeitstrahl');
const historicalEntry = page.locator('li').filter({ hasText: historicalTitle }).first();
await expect(historicalEntry).toBeVisible({ timeout: 10000 });
const note = historicalEntry.locator('[data-testid="event-note"]');
await expect(note).toBeVisible();
await expect(note).toContainText(historicalNote);
});
});