From 6c99c6a6709a3a22fa04f6d138c6e5b6bcd7d74a Mon Sep 17 00:00:00 2001 From: Marcel Date: Wed, 22 Apr 2026 11:00:56 +0200 Subject: [PATCH] test(nav): add E2E tests for BackButton navigation and accessibility Co-Authored-By: Claude Sonnet 4.6 --- frontend/e2e/back-button.spec.ts | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 frontend/e2e/back-button.spec.ts diff --git a/frontend/e2e/back-button.spec.ts b/frontend/e2e/back-button.spec.ts new file mode 100644 index 00000000..4bfa0f66 --- /dev/null +++ b/frontend/e2e/back-button.spec.ts @@ -0,0 +1,58 @@ +import AxeBuilder from '@axe-core/playwright'; +import { test, expect } from '@playwright/test'; + +test.describe('BackButton — navigation', () => { + test('returns to previous page via history when clicked', async ({ page }) => { + // Navigate to persons list, then to a person detail + await page.goto('/persons'); + await page.waitForSelector('[data-hydrated]'); + + const firstPersonLink = page.locator('a[href^="/persons/"]').first(); + const personHref = await firstPersonLink.getAttribute('href'); + await firstPersonLink.click(); + await page.waitForURL(/\/persons\/.+/); + + // Now navigate to the edit page from the detail page + const editLink = page.locator('a[href$="/edit"]').first(); + await editLink.click(); + await page.waitForURL(/\/persons\/.+\/edit/); + + // Click the BackButton — should return to person detail, not /persons list + const backBtn = page.getByRole('button', { name: /zurück/i }); + await expect(backBtn).toBeVisible(); + await backBtn.click(); + + // Should return to the person detail URL (history.back()), not the static /persons + await expect(page).toHaveURL(new RegExp(personHref!.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))); + }); +}); + +test.describe('BackButton — accessibility', () => { + test('touch target is at least 44px tall on /persons/new', async ({ page }) => { + await page.goto('/persons/new'); + await page.waitForSelector('[data-hydrated]'); + + const backBtn = page.getByRole('button', { name: /zurück/i }); + await expect(backBtn).toBeVisible(); + + const box = await backBtn.boundingBox(); + expect(box).not.toBeNull(); + expect(box!.height).toBeGreaterThanOrEqual(44); + }); + + test('passes axe-core wcag2a/wcag2aa scan on /persons/new', async ({ page }) => { + await page.goto('/persons/new'); + await page.waitForSelector('[data-hydrated]'); + + const results = await new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']).analyze(); + + if (results.violations.length > 0) { + const summary = results.violations + .map((v) => `[${v.impact}] ${v.id}: ${v.description}`) + .join('\n'); + console.log(`\nAxe violations on /persons/new:\n${summary}`); + } + + expect(results.violations).toEqual([]); + }); +});