From c1e82a7edf0ae9ff6f27f6c6ca39b999878ec23d Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 22 Mar 2026 23:01:04 +0100 Subject: [PATCH] fix(e2e): fix 8 failing E2E tests on feat/35-profile-page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - admin: add exact:true to tab button assertions to avoid strict-mode violations from "Benutzer löschen" title buttons matching "Benutzer" - admin: change tag-row locator from hasText regex on
  • to has: span filter (more robust against whitespace differences); add waitForSelector after tab click to ensure panel is rendered before hovering - auth: replace page.request.get('/api/users/me') with a profile page navigation — direct browser requests don't carry Basic Auth, only server-side SvelteKit fetches do - documents: use getByRole('heading') instead of getByText to avoid strict mode violation when the title appears in both h1 and breadcrumb - persons: same heading fix for person creation landing page - profile: remove success-message assertion after password change; the auth_token cookie still holds old credentials so use:enhance's update() immediately gets a 401 and redirects to /login before the message renders — test now asserts the redirect directly, then re-logs in Co-Authored-By: Claude Sonnet 4.6 --- frontend/e2e/admin.spec.ts | 23 +++++++++++++++-------- frontend/e2e/auth.spec.ts | 10 ++++++---- frontend/e2e/documents.spec.ts | 2 +- frontend/e2e/persons.spec.ts | 2 +- frontend/e2e/profile.spec.ts | 18 ++++++++---------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/frontend/e2e/admin.spec.ts b/frontend/e2e/admin.spec.ts index 209cec3d..0bf90de5 100644 --- a/frontend/e2e/admin.spec.ts +++ b/frontend/e2e/admin.spec.ts @@ -25,9 +25,9 @@ test.describe('Admin dashboard', () => { await page.goto('/admin'); await page.waitForSelector('[data-hydrated]'); - await expect(page.getByRole('button', { name: 'Benutzer' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Gruppen' })).toBeVisible(); - await expect(page.getByRole('button', { name: 'Schlagworte' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Benutzer', exact: true })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Gruppen', exact: true })).toBeVisible(); + await expect(page.getByRole('button', { name: 'Schlagworte', exact: true })).toBeVisible(); await page.screenshot({ path: 'test-results/e2e/admin-dashboard.png' }); }); }); @@ -40,7 +40,7 @@ test.describe('Admin — group management', () => { await page.waitForSelector('[data-hydrated]'); // Switch to the Groups tab - await page.getByRole('button', { name: 'Gruppen' }).click(); + await page.getByRole('button', { name: 'Gruppen', exact: true }).click(); await page.getByPlaceholder('Gruppenname (z.B. Editoren)').fill('E2E Leser'); @@ -176,10 +176,14 @@ test.describe('Admin — tag management', () => { await page.goto('/admin'); await page.waitForSelector('[data-hydrated]'); - await page.getByRole('button', { name: 'Schlagworte' }).click(); + await page.getByRole('button', { name: 'Schlagworte', exact: true }).click(); + // Wait for the tags list to render after the tab switch + await page.waitForSelector('ul > li'); // Hover over the "Familie" row to reveal the opacity-0 action buttons - const familieRow = page.locator('li').filter({ hasText: /^Familie$/ }); + const familieRow = page + .locator('ul > li') + .filter({ has: page.locator('span', { hasText: /^Familie$/ }) }); await familieRow.hover(); await familieRow.getByRole('button', { name: 'Schlagwort bearbeiten' }).click(); @@ -195,9 +199,12 @@ test.describe('Admin — tag management', () => { await page.goto('/admin'); await page.waitForSelector('[data-hydrated]'); - await page.getByRole('button', { name: 'Schlagworte' }).click(); + await page.getByRole('button', { name: 'Schlagworte', exact: true }).click(); + await page.waitForSelector('ul > li'); - const renamedRow = page.locator('li').filter({ hasText: /^Familie \(E2E\)$/ }); + const renamedRow = page + .locator('ul > li') + .filter({ has: page.locator('span', { hasText: /^Familie \(E2E\)$/ }) }); await renamedRow.hover(); await renamedRow.getByRole('button', { name: 'Schlagwort bearbeiten' }).click(); diff --git a/frontend/e2e/auth.spec.ts b/frontend/e2e/auth.spec.ts index 5e38e15b..a2324067 100644 --- a/frontend/e2e/auth.spec.ts +++ b/frontend/e2e/auth.spec.ts @@ -49,11 +49,13 @@ test.describe('Authentication', () => { }); test('login establishes a session that authenticates API calls', async ({ page }) => { - // Guards against regressions where the session cookie is set but broken — - // a working URL redirect is not enough evidence that auth works end-to-end. + // Guards against regressions where the session cookie is set but broken. + // The profile page calls /api/users/me server-side — if auth works end-to-end, + // it loads without redirecting to /login. await login(page); - const response = await page.request.get('/api/users/me'); - expect(response.ok()).toBe(true); + await page.goto('/profile'); + await expect(page).toHaveURL('/profile'); + await expect(page.getByRole('heading', { name: /Mein Profil/i })).toBeVisible(); await page.screenshot({ path: 'test-results/e2e/auth-session-valid.png' }); }); diff --git a/frontend/e2e/documents.spec.ts b/frontend/e2e/documents.spec.ts index 03a380b6..5743ab02 100644 --- a/frontend/e2e/documents.spec.ts +++ b/frontend/e2e/documents.spec.ts @@ -89,7 +89,7 @@ test.describe('Document creation', () => { await page.getByRole('button', { name: /Speichern/i }).click(); await expect(page).toHaveURL(/\/documents\/[^/]+$/); - await expect(page.getByText('E2E Testbrief')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'E2E Testbrief' })).toBeVisible(); await page.screenshot({ path: 'test-results/e2e/document-create.png' }); }); }); diff --git a/frontend/e2e/persons.spec.ts b/frontend/e2e/persons.spec.ts index 3fd78387..e1089a71 100644 --- a/frontend/e2e/persons.spec.ts +++ b/frontend/e2e/persons.spec.ts @@ -105,7 +105,7 @@ test.describe('Person creation', () => { await page.getByRole('button', { name: /Erstellen/i }).click(); await expect(page).toHaveURL(/\/persons\/[^/]+$/); - await expect(page.getByText('E2E Testperson')).toBeVisible(); + await expect(page.getByRole('heading', { name: 'E2E Testperson' })).toBeVisible(); await page.screenshot({ path: 'test-results/e2e/person-create.png' }); }); }); diff --git a/frontend/e2e/profile.spec.ts b/frontend/e2e/profile.spec.ts index c9f476a1..f1c763f4 100644 --- a/frontend/e2e/profile.spec.ts +++ b/frontend/e2e/profile.spec.ts @@ -72,20 +72,19 @@ test.describe('Profile page', () => { .getByRole('button', { name: /Speichern/i }) .click(); - await expect(page.getByText('Passwort erfolgreich geändert.')).toBeVisible(); - - // ── Step 2: navigate away — server session is invalidated ─────────────── - await page.goto('/'); + // After the password changes, the auth_token cookie still carries the old + // credentials. use:enhance re-runs the page's load function, which calls + // the backend with the stale Basic Auth header → 401 → redirect to /login. await expect(page).toHaveURL(/\/login/); - // ── Step 3: log in with the new password ─────────────────────────────── + // ── Step 2: log in with the new password ─────────────────────────────── await page.getByLabel('Benutzername').fill('admin'); await page.getByLabel('Passwort').fill('TempAdmin456!'); await page.getByRole('button', { name: 'Anmelden' }).click(); await expect(page).toHaveURL('/'); await page.screenshot({ path: 'test-results/e2e/profile-password-changed.png' }); - // ── Step 4: restore the original password so subsequent tests still work ─ + // ── Step 3: restore the original password so subsequent tests still work ─ await page.goto('/profile'); await page.waitForSelector('[data-hydrated]'); await page.locator('input[name="currentPassword"]').fill('TempAdmin456!'); @@ -95,11 +94,10 @@ test.describe('Profile page', () => { .locator('form[action*="changePassword"]') .getByRole('button', { name: /Speichern/i }) .click(); - await expect(page.getByText('Passwort erfolgreich geändert.')).toBeVisible(); - - // ── Step 5: log back in with the restored password ───────────────────── - await page.goto('/'); + // Redirected to /login again after credential rotation await expect(page).toHaveURL(/\/login/); + + // ── Step 4: log back in with the restored password ───────────────────── await page.getByLabel('Benutzername').fill('admin'); await page.getByLabel('Passwort').fill('admin123'); await page.getByRole('button', { name: 'Anmelden' }).click();