Files
familienarchiv/frontend/e2e/profile.spec.ts
Marcel c1e82a7edf fix(e2e): fix 8 failing E2E tests on feat/35-profile-page
- 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 <li> 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 <noreply@anthropic.com>
2026-03-22 23:01:04 +01:00

107 lines
4.6 KiB
TypeScript

import { test, expect } from '@playwright/test';
/**
* Profile page E2E tests.
*
* Reads top-to-bottom as a single user journey:
* the logged-in admin opens their profile, updates their display name,
* tries a wrong password (sees an error), then successfully changes their
* password and logs back in with the new one.
*
* The password change test restores the original password at the end so the
* shared session remains valid for all subsequent test files.
*/
test.describe('Profile page', () => {
test('user opens their profile and sees the personal data and password sections', async ({
page
}) => {
await page.goto('/profile');
await expect(page.getByRole('heading', { name: /Mein Profil/i })).toBeVisible();
await expect(page.getByText('Persönliche Daten')).toBeVisible();
await expect(page.getByText('Passwort ändern')).toBeVisible();
await page.screenshot({ path: 'test-results/e2e/profile-view.png' });
});
test('user saves updated first and last name and sees confirmation', async ({ page }) => {
await page.goto('/profile');
await page.waitForSelector('[data-hydrated]');
await page.locator('input[name="firstName"]').fill('E2E');
await page.locator('input[name="lastName"]').fill('Admin');
// Two "Speichern" buttons exist — the first belongs to the profile form
await page
.locator('form[action*="updateProfile"]')
.getByRole('button', { name: /Speichern/i })
.click();
await expect(page.getByText('Gespeichert.')).toBeVisible();
// Nav avatar shows the new initials derived from firstName + lastName
await expect(page.locator('button[aria-haspopup="true"]')).toContainText('EA');
await page.screenshot({ path: 'test-results/e2e/profile-save.png' });
});
test('shows an error when the current password is wrong', async ({ page }) => {
await page.goto('/profile');
await page.waitForSelector('[data-hydrated]');
await page.locator('input[name="currentPassword"]').fill('definitely-wrong');
await page.locator('input[name="newPassword"]').fill('NewPass123!');
await page.locator('input[name="confirmPassword"]').fill('NewPass123!');
await page
.locator('form[action*="changePassword"]')
.getByRole('button', { name: /Speichern/i })
.click();
await expect(page.getByText('Das aktuelle Passwort ist falsch.')).toBeVisible();
await page.screenshot({ path: 'test-results/e2e/profile-wrong-password.png' });
});
test('user changes their password and can log in with the new one', async ({ page }) => {
await page.goto('/profile');
await page.waitForSelector('[data-hydrated]');
// ── Step 1: change to a temporary password ─────────────────────────────
await page.locator('input[name="currentPassword"]').fill('admin123');
await page.locator('input[name="newPassword"]').fill('TempAdmin456!');
await page.locator('input[name="confirmPassword"]').fill('TempAdmin456!');
await page
.locator('form[action*="changePassword"]')
.getByRole('button', { name: /Speichern/i })
.click();
// 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 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 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!');
await page.locator('input[name="newPassword"]').fill('admin123');
await page.locator('input[name="confirmPassword"]').fill('admin123');
await page
.locator('form[action*="changePassword"]')
.getByRole('button', { name: /Speichern/i })
.click();
// 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();
await expect(page).toHaveURL('/');
});
});