Rewires briefwechsel-rows.visual.spec.ts against the shared fixture (seedBilateralPair + cleanupBilateralPair), adds afterAll cleanup, and folds the conv-person-bar visibility gate into openBilateral() so both the structural test and the snapshot block fail loudly on a hero-state regression — matching the a11y spec's safety net. Refs #305 Fixes @saraholt follow-ups 1 + 2 + 3 from PR round-2 review Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
||
import {
|
||
seedBilateralPair,
|
||
cleanupBilateralPair,
|
||
type BilateralPair
|
||
} from './fixtures/bilateral-correspondence';
|
||
|
||
// Visual + structural coverage for the new briefwechsel row layout.
|
||
//
|
||
// Seeds a bilateral correspondence pair via the shared fixture so the page
|
||
// reaches the row state. The structural test asserts that a
|
||
// ConversationThumbnail tile AND the DistributionBar render — regressions
|
||
// that silently drop to the hero or break the {#each} wiring fail here.
|
||
//
|
||
// Snapshot assertions are gated on the VISUAL env flag because they need
|
||
// pre-captured baselines (see `playwright test --update-snapshots` to
|
||
// regenerate after intentional UI changes). CI can opt in via VISUAL=1.
|
||
const VISUAL = process.env.VISUAL === '1';
|
||
|
||
let pair: BilateralPair;
|
||
|
||
test.describe('Briefwechsel — thumbnail-row layout', () => {
|
||
test.beforeAll(async ({ request }) => {
|
||
pair = await seedBilateralPair(request, 'Visual');
|
||
});
|
||
|
||
test.afterAll(async ({ request }) => {
|
||
await cleanupBilateralPair(request, pair);
|
||
});
|
||
|
||
async function openBilateral(page: import('@playwright/test').Page) {
|
||
await page.goto(
|
||
`/briefwechsel?senderId=${encodeURIComponent(pair.senderId)}&receiverId=${encodeURIComponent(pair.receiverId)}`
|
||
);
|
||
await page.waitForSelector('[data-hydrated]');
|
||
// Parity with the a11y spec: fail loudly if we ever end up on the hero
|
||
// instead of the row layout.
|
||
await expect(page.getByTestId('conv-person-bar')).toBeVisible();
|
||
}
|
||
|
||
test('renders a ConversationThumbnail tile and the DistributionBar', async ({ page }) => {
|
||
await openBilateral(page);
|
||
|
||
// Tile appears for the seeded document
|
||
await expect(page.locator('[data-testid="conv-thumb-tile"]').first()).toBeVisible();
|
||
|
||
// DistributionBar is present (role=img with a descriptive aria-label)
|
||
const bar = page.locator('[role="img"]');
|
||
await expect(bar).toBeVisible();
|
||
const label = (await bar.getAttribute('aria-label')) ?? '';
|
||
expect(label.length).toBeGreaterThan(0);
|
||
});
|
||
|
||
// Visual regression — one snapshot per (viewport × theme). Tolerance stays
|
||
// generous (maxDiffPixels: 100) so antialiasing jitter doesn't flip them on
|
||
// unrelated runs; genuine layout changes are still caught because the
|
||
// thumbnail tile and distribution bar dominate the frame.
|
||
test.describe('snapshots', () => {
|
||
test.skip(!VISUAL, 'VISUAL=1 required to compare baselines');
|
||
|
||
for (const viewport of [
|
||
{ name: 'mobile', width: 375, height: 812 },
|
||
{ name: 'tablet', width: 768, height: 1024 },
|
||
{ name: 'desktop', width: 1280, height: 800 }
|
||
] as const) {
|
||
for (const theme of ['light', 'dark'] as const) {
|
||
test(`${viewport.name} / ${theme}`, async ({ page }) => {
|
||
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
||
await page.emulateMedia({ colorScheme: theme });
|
||
await openBilateral(page);
|
||
await expect(page).toHaveScreenshot(`briefwechsel-${viewport.name}-${theme}.png`, {
|
||
maxDiffPixels: 100,
|
||
fullPage: true
|
||
});
|
||
});
|
||
}
|
||
}
|
||
});
|
||
});
|