feat(briefwechsel): thumbnail rows with summary quote and bilateral distribution bar (#305) #311
@@ -1,8 +1,13 @@
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
seedBilateralPair,
|
||||
cleanupBilateralPair,
|
||||
type BilateralPair
|
||||
} from './fixtures/bilateral-correspondence';
|
||||
|
||||
// Accessibility coverage specifically for the briefwechsel thumbnail-row
|
||||
// layout. Seeds two persons + a bilateral document via the API so the page
|
||||
// Accessibility coverage for the briefwechsel thumbnail-row layout. Seeds
|
||||
// two persons + a bilateral document via the shared fixture so the page
|
||||
// reaches the results state (not the hero), then runs axe-core
|
||||
// (wcag2a + wcag2aa) across three viewports and two color schemes.
|
||||
|
||||
@@ -14,33 +19,15 @@ const VIEWPORTS = [
|
||||
|
||||
const THEMES = ['light', 'dark'] as const;
|
||||
|
||||
let senderId: string;
|
||||
let receiverId: string;
|
||||
let pair: BilateralPair;
|
||||
|
||||
test.describe('Accessibility — /briefwechsel row layout', () => {
|
||||
test.beforeAll(async ({ request }) => {
|
||||
const timestamp = Date.now();
|
||||
const senderRes = await request.post('/api/persons', {
|
||||
data: { firstName: 'A11y', lastName: `Sender-${timestamp}` }
|
||||
});
|
||||
if (!senderRes.ok()) throw new Error(`Create sender failed: ${senderRes.status()}`);
|
||||
senderId = (await senderRes.json()).id;
|
||||
pair = await seedBilateralPair(request, 'A11y');
|
||||
});
|
||||
|
||||
const receiverRes = await request.post('/api/persons', {
|
||||
data: { firstName: 'A11y', lastName: `Receiver-${timestamp}` }
|
||||
});
|
||||
if (!receiverRes.ok()) throw new Error(`Create receiver failed: ${receiverRes.status()}`);
|
||||
receiverId = (await receiverRes.json()).id;
|
||||
|
||||
const docRes = await request.post('/api/documents', {
|
||||
multipart: {
|
||||
title: 'A11y Test Brief',
|
||||
documentDate: '1950-06-15',
|
||||
senderId,
|
||||
receiverIds: receiverId
|
||||
}
|
||||
});
|
||||
if (!docRes.ok()) throw new Error(`Create document failed: ${docRes.status()}`);
|
||||
test.afterAll(async ({ request }) => {
|
||||
await cleanupBilateralPair(request, pair);
|
||||
});
|
||||
|
||||
for (const vp of VIEWPORTS) {
|
||||
@@ -49,7 +36,7 @@ test.describe('Accessibility — /briefwechsel row layout', () => {
|
||||
await page.setViewportSize({ width: vp.width, height: vp.height });
|
||||
await page.emulateMedia({ colorScheme: theme });
|
||||
await page.goto(
|
||||
`/briefwechsel?senderId=${encodeURIComponent(senderId)}&receiverId=${encodeURIComponent(receiverId)}`
|
||||
`/briefwechsel?senderId=${encodeURIComponent(pair.senderId)}&receiverId=${encodeURIComponent(pair.receiverId)}`
|
||||
);
|
||||
await page.waitForSelector('[data-hydrated]');
|
||||
|
||||
|
||||
62
frontend/e2e/fixtures/bilateral-correspondence.ts
Normal file
62
frontend/e2e/fixtures/bilateral-correspondence.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { APIRequestContext } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Test fixture for the briefwechsel row layout.
|
||||
*
|
||||
* Creates two persons and one document with sender/receiver between them so
|
||||
* that `/briefwechsel?senderId=X&receiverId=Y` navigates straight to the row
|
||||
* state (not the hero). Each seed uses a `Date.now()`-suffixed last name so
|
||||
* parallel runs and reruns never collide.
|
||||
*
|
||||
* The backend does not expose a person-delete endpoint, so only the document
|
||||
* is cleaned up in {@link cleanupBilateralPair}. The two timestamped persons
|
||||
* remain in the DB — acceptable for the test environment, and the unique
|
||||
* suffix means they cannot conflict with later runs.
|
||||
*/
|
||||
|
||||
export interface BilateralPair {
|
||||
senderId: string;
|
||||
receiverId: string;
|
||||
documentId: string;
|
||||
}
|
||||
|
||||
export async function seedBilateralPair(
|
||||
request: APIRequestContext,
|
||||
prefix: string
|
||||
): Promise<BilateralPair> {
|
||||
const timestamp = Date.now();
|
||||
|
||||
const senderRes = await request.post('/api/persons', {
|
||||
data: { firstName: prefix, lastName: `Sender-${timestamp}` }
|
||||
});
|
||||
if (!senderRes.ok()) throw new Error(`Create sender failed: ${senderRes.status()}`);
|
||||
const senderId = (await senderRes.json()).id as string;
|
||||
|
||||
const receiverRes = await request.post('/api/persons', {
|
||||
data: { firstName: prefix, lastName: `Receiver-${timestamp}` }
|
||||
});
|
||||
if (!receiverRes.ok()) throw new Error(`Create receiver failed: ${receiverRes.status()}`);
|
||||
const receiverId = (await receiverRes.json()).id as string;
|
||||
|
||||
const docRes = await request.post('/api/documents', {
|
||||
multipart: {
|
||||
title: `${prefix} Brief`,
|
||||
documentDate: '1950-06-15',
|
||||
senderId,
|
||||
receiverIds: receiverId
|
||||
}
|
||||
});
|
||||
if (!docRes.ok()) throw new Error(`Create document failed: ${docRes.status()}`);
|
||||
const documentId = (await docRes.json()).id as string;
|
||||
|
||||
return { senderId, receiverId, documentId };
|
||||
}
|
||||
|
||||
export async function cleanupBilateralPair(
|
||||
request: APIRequestContext,
|
||||
pair: BilateralPair
|
||||
): Promise<void> {
|
||||
// Only the document is purged — the backend has no person-delete endpoint
|
||||
// and the timestamped last names make orphaned person rows safe to leave.
|
||||
await request.delete(`/api/documents/${pair.documentId}`);
|
||||
}
|
||||
Reference in New Issue
Block a user