test(coverage): drive browser tests to 80% on all metrics (#496) #505

Merged
marcel merged 189 commits from feat/issue-496-browser-coverage-tests into main 2026-05-11 21:50:39 +02:00
Showing only changes of commit 170a770d6f - Show all commits

View File

@@ -0,0 +1,121 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
const mockPage = { url: { pathname: '/admin/tags/t1' } };
vi.mock('$app/stores', () => ({
page: {
subscribe: (fn: (v: typeof mockPage) => void) => {
fn(mockPage);
return () => {};
}
}
}));
vi.mock('$lib/shared/services/confirm.svelte', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
vi.mock('$lib/shared/services/confirm.svelte.js', () => ({
getConfirmService: () => ({ confirm: async () => false })
}));
vi.mock('$app/navigation', () => ({
beforeNavigate: () => {},
afterNavigate: () => {},
goto: vi.fn(),
invalidate: vi.fn(),
invalidateAll: vi.fn(),
preloadCode: vi.fn(),
preloadData: vi.fn(),
pushState: vi.fn(),
replaceState: vi.fn(),
disableScrollHandling: vi.fn(),
onNavigate: () => () => {}
}));
const { default: AdminTagEditPage } = await import('./+page.svelte');
afterEach(cleanup);
const baseTag = (overrides: Record<string, unknown> = {}) => ({
id: 't1',
name: 'Personen',
color: 'sage' as string | null,
parentId: null as string | null,
...overrides
});
const baseData = (overrides: Record<string, unknown> = {}) => ({
tag: baseTag(),
tags: [baseTag(), baseTag({ id: 't2', name: 'Orte', color: 'sienna' })],
mergeSuccess: null,
...overrides
});
describe('admin/tags/[id] page', () => {
it('renders the edit heading with the tag name', async () => {
render(AdminTagEditPage, { props: { data: baseData(), form: undefined } });
await expect.element(page.getByRole('heading', { name: /personen/i })).toBeVisible();
});
it('hydrates the name input from data.tag.name', async () => {
render(AdminTagEditPage, {
props: { data: baseData({ tag: baseTag({ name: 'Reisen' }) }), form: undefined }
});
const input = document.querySelector('input[name="name"]') as HTMLInputElement;
expect(input.value).toBe('Reisen');
});
it('renders the color picker for top-level tags (no parentId)', async () => {
render(AdminTagEditPage, { props: { data: baseData(), form: undefined } });
const colorPicker = document.querySelector('[data-testid="color-picker"]');
expect(colorPicker).not.toBeNull();
});
it('renders one color swatch per palette entry', async () => {
render(AdminTagEditPage, { props: { data: baseData(), form: undefined } });
const swatches = document.querySelectorAll('[data-testid^="color-swatch-"]');
expect(swatches.length).toBeGreaterThanOrEqual(10);
});
it('marks the active color swatch as aria-pressed', async () => {
render(AdminTagEditPage, {
props: { data: baseData({ tag: baseTag({ color: 'amber' }) }), form: undefined }
});
const amberSwatch = document.querySelector('[data-testid="color-swatch-amber"]') as HTMLElement;
expect(amberSwatch.getAttribute('aria-pressed')).toBe('true');
});
it('shows the form-success banner when form.success is true', async () => {
render(AdminTagEditPage, {
props: { data: baseData(), form: { success: true } }
});
const banners = document.querySelectorAll('.bg-green-50');
expect(banners.length).toBeGreaterThan(0);
});
it('shows the form-error banner when form.error is set', async () => {
render(AdminTagEditPage, {
props: { data: baseData(), form: { error: 'Tag name already in use' } }
});
const errors = document.querySelectorAll('.bg-red-50');
expect(errors.length).toBeGreaterThan(0);
});
it('shows the merge-success banner when data.mergeSuccess is set', async () => {
render(AdminTagEditPage, {
props: { data: baseData({ mergeSuccess: 'old-id' }), form: undefined }
});
const banners = document.querySelectorAll('[role="status"]');
expect(banners.length).toBeGreaterThan(0);
});
});