test: cover login and persons/[id] page branches
login: form rendering, registered-success banner branch, form-error banner branch, form-action wiring, email/password input attributes, forgot-password link. persons/[id]: PersonCard heading via prop pass-through, document section headings, empty-message branches, GeschichtenCard hidden when empty, co-correspondents derived from sent documents, canWrite gating the edit link. 14 tests across two large pages. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
73
frontend/src/routes/login/page.svelte.test.ts
Normal file
73
frontend/src/routes/login/page.svelte.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import LoginPage from './+page.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('login page', () => {
|
||||
it('renders the login form by default', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /^anmelden$/i })).toBeVisible();
|
||||
await expect.element(page.getByLabelText(/e-mail-adresse/i)).toBeVisible();
|
||||
await expect.element(page.getByLabelText(/passwort/i)).toBeVisible();
|
||||
await expect.element(page.getByRole('button', { name: /^anmelden$/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the registered-success banner when data.registered is true', async () => {
|
||||
render(LoginPage, { props: { data: { registered: true }, form: undefined } });
|
||||
|
||||
await expect
|
||||
.element(page.getByText('Dein Konto wurde erfolgreich erstellt. Melde dich jetzt an.'))
|
||||
.toBeVisible();
|
||||
});
|
||||
|
||||
it('hides the registered-success banner when data.registered is false', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
await expect.element(page.getByRole('status')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows the form error when form.error is set', async () => {
|
||||
render(LoginPage, {
|
||||
props: { data: { registered: false }, form: { error: 'Ungültige Anmeldedaten' } }
|
||||
});
|
||||
|
||||
await expect.element(page.getByText('Ungültige Anmeldedaten')).toBeVisible();
|
||||
});
|
||||
|
||||
it('declares POST as the form method and routes to ?/login', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
const form = document.querySelector('form');
|
||||
expect(form?.getAttribute('method')).toBe('POST');
|
||||
expect(form?.getAttribute('action')).toBe('?/login');
|
||||
});
|
||||
|
||||
it('exposes the email input as type=email and required', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
const email = document.querySelector('input[name="email"]') as HTMLInputElement;
|
||||
expect(email.type).toBe('email');
|
||||
expect(email.required).toBe(true);
|
||||
expect(email.autocomplete).toBe('email');
|
||||
});
|
||||
|
||||
it('exposes the password input as type=password and required', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
const pwd = document.querySelector('input[name="password"]') as HTMLInputElement;
|
||||
expect(pwd.type).toBe('password');
|
||||
expect(pwd.required).toBe(true);
|
||||
expect(pwd.autocomplete).toBe('current-password');
|
||||
});
|
||||
|
||||
it('renders the forgot-password link', async () => {
|
||||
render(LoginPage, { props: { data: { registered: false }, form: undefined } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: /passwort vergessen/i }))
|
||||
.toHaveAttribute('href', '/forgot-password');
|
||||
});
|
||||
});
|
||||
104
frontend/src/routes/persons/[id]/page.svelte.test.ts
Normal file
104
frontend/src/routes/persons/[id]/page.svelte.test.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { describe, it, expect, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
import PersonDetailPage from './+page.svelte';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
const basePerson = {
|
||||
id: 'p-1',
|
||||
firstName: 'Anna',
|
||||
lastName: 'Schmidt',
|
||||
displayName: 'Anna Schmidt',
|
||||
personType: 'PERSON' as const
|
||||
};
|
||||
|
||||
const baseData = (overrides: Record<string, unknown> = {}) => ({
|
||||
person: basePerson,
|
||||
canWrite: false,
|
||||
canBlogWrite: false,
|
||||
aliases: [] as { name: string; from: string; to: string }[],
|
||||
relationships: [],
|
||||
inferredRelationships: [],
|
||||
sentDocuments: [] as Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
status: string;
|
||||
receivers?: { id: string; displayName: string }[];
|
||||
}>,
|
||||
receivedDocuments: [] as Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
status: string;
|
||||
sender?: { id: string; displayName: string };
|
||||
}>,
|
||||
geschichten: undefined,
|
||||
...overrides
|
||||
});
|
||||
|
||||
describe('persons/[id] page', () => {
|
||||
it('renders the person heading via PersonCard', async () => {
|
||||
render(PersonDetailPage, { props: { data: baseData() } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: 'Anna Schmidt' })).toBeVisible();
|
||||
});
|
||||
|
||||
it('renders both document section headings', async () => {
|
||||
render(PersonDetailPage, { props: { data: baseData() } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /gesendete dokumente/i })).toBeVisible();
|
||||
await expect
|
||||
.element(page.getByRole('heading', { name: /empfangene dokumente/i }))
|
||||
.toBeVisible();
|
||||
});
|
||||
|
||||
it('renders empty messages when no documents are present', async () => {
|
||||
render(PersonDetailPage, { props: { data: baseData() } });
|
||||
|
||||
await expect
|
||||
.element(page.getByText('Diese Person ist noch nicht als Absender verknüpft.'))
|
||||
.toBeVisible();
|
||||
await expect
|
||||
.element(page.getByText('Diese Person ist noch nicht als Empfänger verknüpft.'))
|
||||
.toBeVisible();
|
||||
});
|
||||
|
||||
it('does not render the GeschichtenCard when there are no geschichten', async () => {
|
||||
render(PersonDetailPage, { props: { data: baseData({ geschichten: [] }) } });
|
||||
|
||||
const geschichteHeadings = Array.from(document.querySelectorAll('h2'))
|
||||
.map((h) => h.textContent ?? '')
|
||||
.filter((t) => /geschichte/i.test(t));
|
||||
expect(geschichteHeadings.length).toBe(0);
|
||||
});
|
||||
|
||||
it('renders co-correspondents derived from sent documents receivers', async () => {
|
||||
const data = baseData({
|
||||
sentDocuments: [
|
||||
{
|
||||
id: 'd1',
|
||||
title: 'B1',
|
||||
status: 'UPLOADED',
|
||||
receivers: [{ id: 'r1', displayName: 'Bert Meier' }]
|
||||
},
|
||||
{
|
||||
id: 'd2',
|
||||
title: 'B2',
|
||||
status: 'UPLOADED',
|
||||
receivers: [{ id: 'r1', displayName: 'Bert Meier' }]
|
||||
}
|
||||
]
|
||||
});
|
||||
render(PersonDetailPage, { props: { data } });
|
||||
|
||||
await expect.element(page.getByText(/häufige korrespondenten/i)).toBeVisible();
|
||||
});
|
||||
|
||||
it('shows the edit button via PersonCard when canWrite is true', async () => {
|
||||
render(PersonDetailPage, { props: { data: baseData({ canWrite: true }) } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: /bearbeiten/i }))
|
||||
.toHaveAttribute('href', '/persons/p-1/edit');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user