import { test, expect } from '@playwright/test'; import AxeBuilder from '@axe-core/playwright'; import { createEmptyDocument } from './helpers/upload-empty-document.js'; async function createBlock( request: Parameters[0], docId: string ): Promise { const res = await request.post(`/api/documents/${docId}/transcription-blocks`, { data: { pageNumber: 1, x: 0.1, y: 0.1, width: 0.3, height: 0.1, text: 'Liebe Mutter,', label: null } }); if (!res.ok()) throw new Error(`Create block failed: ${res.status()}`); } function buildAxe(page: Parameters[0]['page']) { return new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']); } test.describe('Transcribe coach — empty state', () => { let docId: string; test.beforeAll(async ({ request }) => { docId = await createEmptyDocument(request); }); test.afterAll(async ({ request }) => { await request.delete(`/api/documents/${docId}`); }); test('shows coach card (title, preamble, three step bodies, animation region)', async ({ page }) => { await page.goto(`/documents/${docId}`); await page.getByRole('button', { name: 'Transkribieren' }).click(); await expect(page.getByRole('heading', { level: 2, name: /Erste Transkription/ })).toBeVisible({ timeout: 5000 }); await expect(page.getByText(/Kurrent-Erkenner lernt noch/)).toBeVisible(); await expect(page.getByText(/Rahmen ziehen/)).toBeVisible(); await expect(page.getByText(/Text eingeben/)).toBeVisible(); await expect(page.getByText(/Speichert automatisch/)).toBeVisible(); await expect(page.getByRole('img', { name: /Rahmen ziehen|Animation/i })).toBeVisible(); }); test('training footer is NOT visible on empty doc', async ({ page }) => { await page.goto(`/documents/${docId}`); await page.getByRole('button', { name: 'Transkribieren' }).click(); await expect(page.getByText('Für Training vormerken')).not.toBeVisible({ timeout: 3000 }); }); test('axe: panel empty state — light theme — no WCAG 2.1 AA violations', async ({ page }) => { await page.goto(`/documents/${docId}`); await page.getByRole('button', { name: 'Transkribieren' }).click(); await expect(page.getByRole('heading', { level: 2, name: /Erste Transkription/ })).toBeVisible({ timeout: 5000 }); const a11y = await buildAxe(page).analyze(); expect(a11y.violations, JSON.stringify(a11y.violations, null, 2)).toHaveLength(0); }); test('axe: panel empty state — dark theme — no WCAG 2.1 AA violations', async ({ page }) => { await page.goto(`/documents/${docId}`); // Toggle dark theme await page.getByRole('button', { name: /dark mode/i }).click(); await page.getByRole('button', { name: 'Transkribieren' }).click(); await expect(page.getByRole('heading', { level: 2, name: /Erste Transkription/ })).toBeVisible({ timeout: 5000 }); const a11y = await buildAxe(page).analyze(); expect(a11y.violations, JSON.stringify(a11y.violations, null, 2)).toHaveLength(0); }); }); test.describe('Transcribe coach — with blocks', () => { let docId: string; test.beforeAll(async ({ request }) => { docId = await createEmptyDocument(request); await createBlock(request, docId); }); test.afterAll(async ({ request }) => { await request.delete(`/api/documents/${docId}`); }); test('training footer IS visible when at least one block exists', async ({ page }) => { await page.goto(`/documents/${docId}`); await page.getByRole('button', { name: 'Transkribieren' }).click(); // Wait for blocks to finish loading — block count confirms mode settled to 'read' await expect(page.getByText(/1 Abschnitt/)).toBeVisible({ timeout: 5000 }); await page.locator('[data-testid="mode-edit"]').click(); await expect(page.getByText('Für Training vormerken')).toBeVisible({ timeout: 5000 }); }); });