Some checks failed
CI / Backend Unit Tests (pull_request) Has been cancelled
CI / E2E Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (pull_request) Has been cancelled
CI / Unit & Component Tests (push) Successful in 2m3s
CI / Backend Unit Tests (push) Successful in 2m13s
CI / E2E Tests (push) Successful in 17m49s
Paraglide's client-side setLocale writes the locale via document.cookie,
which silently fails for HttpOnly cookies. SvelteKit's cookies.set()
defaults to httpOnly: true, so locale switching never worked in tests.
Fix by setting httpOnly: false on the locale cookie (it's a UI preference,
not a credential — no security concern).
Add waitForSelector('[data-hydrated]') before any click that relies on
SvelteKit JavaScript event handlers. Without this, the click fires before
hydration and the onclick handler is not yet registered.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
99 lines
4.0 KiB
TypeScript
99 lines
4.0 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Person list', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/persons');
|
|
});
|
|
|
|
test('renders the persons list page', async ({ page }) => {
|
|
await expect(page.getByRole('heading', { name: /Personen/i })).toBeVisible();
|
|
await expect(page.getByRole('link', { name: /Neue Person/i })).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/persons-list.png' });
|
|
});
|
|
|
|
test('search filters the persons list', async ({ page }) => {
|
|
// Navigate directly with the query param — tests that search results are filtered
|
|
// correctly without depending on the debounced oninput → goto chain in CI.
|
|
await page.goto('/persons?q=zzz_unlikely_match');
|
|
await expect(page.getByText(/Keine Personen gefunden/i)).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/persons-search-empty.png' });
|
|
});
|
|
|
|
test('clicking a person opens the detail page', async ({ page }) => {
|
|
const firstPerson = page.locator('a[href^="/persons/"]').first();
|
|
await firstPerson.click();
|
|
await expect(page).toHaveURL(/\/persons\/.+/);
|
|
await page.screenshot({ path: 'test-results/e2e/person-detail.png' });
|
|
});
|
|
});
|
|
|
|
test.describe('Person detail', () => {
|
|
test('shows the person name and their documents', async ({ page }) => {
|
|
await page.goto('/persons');
|
|
const firstPerson = page.locator('a[href^="/persons/"]').first();
|
|
await firstPerson.click();
|
|
// The detail page shows the person's name as the top-level heading
|
|
await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/person-detail-documents.png' });
|
|
});
|
|
|
|
test('can enter and cancel edit mode', async ({ page }) => {
|
|
await page.goto('/persons');
|
|
const firstPerson = page.locator('a[href^="/persons/"]').first();
|
|
await firstPerson.click();
|
|
// Click the edit button
|
|
const editBtn = page.getByRole('button', { name: /Bearbeiten/i });
|
|
if (await editBtn.isVisible()) {
|
|
await editBtn.click();
|
|
await expect(page.getByLabel('Vorname')).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/person-edit-form.png' });
|
|
// Cancel
|
|
await page.getByRole('button', { name: /Abbrechen/i }).click();
|
|
await expect(page.getByLabel('Vorname')).not.toBeVisible();
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('New person', () => {
|
|
test('renders the new person form', async ({ page }) => {
|
|
await page.goto('/persons/new');
|
|
await expect(page.getByLabel('Vorname')).toBeVisible();
|
|
await expect(page.getByLabel('Nachname')).toBeVisible();
|
|
await expect(page.getByRole('button', { name: /Erstellen/i })).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/person-new.png' });
|
|
});
|
|
|
|
test('shows a validation error when submitting with empty fields', async ({ page }) => {
|
|
await page.goto('/persons/new');
|
|
// HTML required attribute prevents submission without filling required fields
|
|
await page.getByRole('button', { name: /Erstellen/i }).click();
|
|
// The form should not have navigated away
|
|
await expect(page).toHaveURL('/persons/new');
|
|
});
|
|
});
|
|
|
|
test.describe('Conversations', () => {
|
|
test('shows the empty state when no persons are selected', async ({ page }) => {
|
|
await page.goto('/conversations');
|
|
await expect(page.getByText(/Wählen Sie zwei Personen aus/i)).toBeVisible();
|
|
await page.screenshot({ path: 'test-results/e2e/conversations-empty.png' });
|
|
});
|
|
|
|
test('nav link is active on the conversations page', async ({ page }) => {
|
|
await page.goto('/conversations');
|
|
const navLink = page.getByRole('link', { name: 'Konversationen' });
|
|
await expect(navLink).toHaveClass(/text-brand-navy/);
|
|
});
|
|
|
|
test('sort toggle changes the button label', async ({ page }) => {
|
|
await page.goto('/conversations');
|
|
await page.waitForSelector('[data-hydrated]');
|
|
const btn = page.getByRole('button', { name: /Sortierung/i });
|
|
await expect(btn).toContainText('Neueste zuerst');
|
|
await btn.click();
|
|
await expect(page).toHaveURL(/dir=ASC/);
|
|
await expect(btn).toContainText('Älteste zuerst');
|
|
await page.screenshot({ path: 'test-results/e2e/conversations-sort.png' });
|
|
});
|
|
});
|