test(e2e): add training footer positive-case test and fix broken selectors
Some checks failed
CI / Unit & Component Tests (push) Failing after 2m46s
CI / OCR Service Tests (push) Successful in 28s
CI / Backend Unit Tests (push) Failing after 2m51s
CI / Unit & Component Tests (pull_request) Failing after 2m48s
CI / OCR Service Tests (pull_request) Successful in 44s
CI / Backend Unit Tests (pull_request) Failing after 2m59s

- createEmptyDocument now uploads a minimal PDF so the Transkribieren
  button is rendered (requires isPdf = true in DocumentTopBar)
- add 'Transcribe coach — with blocks' describe: seeds a block via API,
  waits for blocks to settle in read mode, switches to edit, confirms
  'Für Training vormerken' is visible
- fix dark-theme axe test: ThemeToggle uses aria-label 'dark mode',
  not the previous /Farbmodus|theme/ regex

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-25 10:22:52 +02:00
parent 7b3334f5e7
commit 534ec9597d
2 changed files with 65 additions and 5 deletions

View File

@@ -1,10 +1,30 @@
import type { APIRequestContext } from '@playwright/test';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PDF_FIXTURE = path.resolve(__dirname, '../fixtures/minimal.pdf');
export async function createEmptyDocument(request: APIRequestContext): Promise<string> {
const res = await request.post('/api/documents', {
const createRes = await request.post('/api/documents', {
multipart: { title: 'E2E Transcribe Coach Test' }
});
if (!res.ok()) throw new Error(`Create document failed: ${res.status()}`);
const doc = await res.json();
return doc.id as string;
if (!createRes.ok()) throw new Error(`Create document failed: ${createRes.status()}`);
const doc = await createRes.json();
const docId = doc.id as string;
const uploadRes = await request.put(`/api/documents/${docId}`, {
multipart: {
title: doc.title,
file: {
name: 'minimal.pdf',
mimeType: 'application/pdf',
buffer: fs.readFileSync(PDF_FIXTURE)
}
}
});
if (!uploadRes.ok()) throw new Error(`Upload PDF failed: ${uploadRes.status()}`);
return docId;
}

View File

@@ -2,6 +2,24 @@ 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<typeof createEmptyDocument>[0],
docId: string
): Promise<void> {
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<typeof AxeBuilder>[0]['page']) {
return new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']);
}
@@ -53,7 +71,7 @@ test.describe('Transcribe coach — empty state', () => {
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: /Farbmodus|theme/i }).click();
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
@@ -63,3 +81,25 @@ test.describe('Transcribe coach — empty state', () => {
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 });
});
});