test(stammbaum): cover empty/populated/preselect/zoom branches
empty state vs. populated, zoom controls visibility tied to node count, URL ?focus= preselection (matching id selects, missing id does not), zoom-out clamping safety. $app/state mocked at module boundary so the test can drive page.url and page.data.canWrite without a SvelteKit runtime. Six tests focused on user-observable behaviour — one logical behaviour per test (Sara's guidance). Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
88
frontend/src/routes/stammbaum/page.svelte.test.ts
Normal file
88
frontend/src/routes/stammbaum/page.svelte.test.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page } from 'vitest/browser';
|
||||
|
||||
const mockPage = {
|
||||
url: new URL('http://localhost/stammbaum'),
|
||||
data: { canWrite: false } as { canWrite: boolean }
|
||||
};
|
||||
|
||||
vi.mock('$app/state', () => ({
|
||||
get page() {
|
||||
return mockPage;
|
||||
}
|
||||
}));
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
async function loadComponent() {
|
||||
return (await import('./+page.svelte')).default;
|
||||
}
|
||||
|
||||
const sampleNodes = [
|
||||
{ id: 'p-1', firstName: 'Anna', lastName: 'Schmidt', displayName: 'Anna Schmidt' },
|
||||
{ id: 'p-2', firstName: 'Bert', lastName: 'Schmidt', displayName: 'Bert Schmidt' }
|
||||
];
|
||||
|
||||
describe('stammbaum page', () => {
|
||||
it('shows the empty state when there are no family nodes', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: [], edges: [] } } });
|
||||
|
||||
await expect
|
||||
.element(page.getByRole('heading', { name: /noch keine familienmitglieder/i }))
|
||||
.toBeVisible();
|
||||
await expect
|
||||
.element(page.getByRole('link', { name: /zur personenliste/i }))
|
||||
.toHaveAttribute('href', '/persons');
|
||||
});
|
||||
|
||||
it('hides zoom controls when there are no nodes', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: [], edges: [] } } });
|
||||
|
||||
await expect.element(page.getByRole('button', { name: /vergrößern/i })).not.toBeInTheDocument();
|
||||
await expect
|
||||
.element(page.getByRole('button', { name: /verkleinern/i }))
|
||||
.not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders the page heading and zoom controls when nodes are present', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: sampleNodes, edges: [] } } });
|
||||
|
||||
await expect.element(page.getByRole('heading', { name: /stammbaum/i })).toBeVisible();
|
||||
await expect.element(page.getByRole('button', { name: /vergrößern/i })).toBeVisible();
|
||||
await expect.element(page.getByRole('button', { name: /verkleinern/i })).toBeVisible();
|
||||
});
|
||||
|
||||
it('preselects a node when the URL has a focus query param matching an existing node', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum?focus=p-1');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: sampleNodes, edges: [] } } });
|
||||
|
||||
await expect.element(page.getByRole('complementary')).toBeVisible();
|
||||
});
|
||||
|
||||
it('does not preselect when the focus param does not match any node', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum?focus=missing');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: sampleNodes, edges: [] } } });
|
||||
|
||||
await expect.element(page.getByRole('complementary')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clamps the zoom level when the zoom-out button is clicked many times', async () => {
|
||||
mockPage.url = new URL('http://localhost/stammbaum');
|
||||
const Stammbaum = await loadComponent();
|
||||
render(Stammbaum, { props: { data: { nodes: sampleNodes, edges: [] } } });
|
||||
|
||||
const zoomOut = page.getByRole('button', { name: /verkleinern/i });
|
||||
for (let i = 0; i < 10; i++) await zoomOut.click();
|
||||
// Just verify that repeated clicks don't throw — branch coverage
|
||||
await expect.element(zoomOut).toBeVisible();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user