test(e2e): add training footer positive-case test and fix broken selectors
- 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:
@@ -1,10 +1,30 @@
|
|||||||
import type { APIRequestContext } from '@playwright/test';
|
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> {
|
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' }
|
multipart: { title: 'E2E Transcribe Coach Test' }
|
||||||
});
|
});
|
||||||
if (!res.ok()) throw new Error(`Create document failed: ${res.status()}`);
|
if (!createRes.ok()) throw new Error(`Create document failed: ${createRes.status()}`);
|
||||||
const doc = await res.json();
|
const doc = await createRes.json();
|
||||||
return doc.id as string;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,24 @@ import { test, expect } from '@playwright/test';
|
|||||||
import AxeBuilder from '@axe-core/playwright';
|
import AxeBuilder from '@axe-core/playwright';
|
||||||
import { createEmptyDocument } from './helpers/upload-empty-document.js';
|
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']) {
|
function buildAxe(page: Parameters<typeof AxeBuilder>[0]['page']) {
|
||||||
return new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']);
|
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 }) => {
|
test('axe: panel empty state — dark theme — no WCAG 2.1 AA violations', async ({ page }) => {
|
||||||
await page.goto(`/documents/${docId}`);
|
await page.goto(`/documents/${docId}`);
|
||||||
// Toggle dark theme
|
// 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 page.getByRole('button', { name: 'Transkribieren' }).click();
|
||||||
await expect(page.getByRole('heading', { level: 2, name: /Erste Transkription/ })).toBeVisible({
|
await expect(page.getByRole('heading', { level: 2, name: /Erste Transkription/ })).toBeVisible({
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
@@ -63,3 +81,25 @@ test.describe('Transcribe coach — empty state', () => {
|
|||||||
expect(a11y.violations, JSON.stringify(a11y.violations, null, 2)).toHaveLength(0);
|
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 });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user