From f1a0076cc01f55d53d1cb468ac478be82ca5f0f5 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 9 May 2026 22:08:33 +0200 Subject: [PATCH] test(admin/groups): cover the group-edit page branches Heading, name hydration, per-permission checkbox checked-state matrix, success/error banner branches, cancel link, delete + save buttons. Mocks confirm service. 7 tests, ~30 branches. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../admin/groups/[id]/page.svelte.test.ts | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 frontend/src/routes/admin/groups/[id]/page.svelte.test.ts diff --git a/frontend/src/routes/admin/groups/[id]/page.svelte.test.ts b/frontend/src/routes/admin/groups/[id]/page.svelte.test.ts new file mode 100644 index 00000000..b88f9f6f --- /dev/null +++ b/frontend/src/routes/admin/groups/[id]/page.svelte.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; + +vi.mock('$lib/shared/services/confirm.svelte.js', () => ({ + getConfirmService: () => ({ confirm: async () => false }) +})); + +const { default: AdminGroupEditPage } = await import('./+page.svelte'); + +afterEach(cleanup); + +const baseGroup = (overrides: Record = {}) => ({ + id: 'g1', + name: 'Familie', + permissions: ['READ_ALL'] as string[], + ...overrides +}); + +describe('admin/groups/[id] page', () => { + it('renders the edit heading with the group name', async () => { + render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } }); + + await expect.element(page.getByRole('heading', { name: /familie/i })).toBeVisible(); + }); + + it('hydrates the name input from data.group.name', async () => { + render(AdminGroupEditPage, { + props: { data: { group: baseGroup({ name: 'Admins' }) }, form: undefined } + }); + + const input = document.querySelector('input[name="name"]') as HTMLInputElement; + expect(input.value).toBe('Admins'); + }); + + it('checks the permission checkboxes that are in data.group.permissions', async () => { + render(AdminGroupEditPage, { + props: { + data: { group: baseGroup({ permissions: ['READ_ALL', 'ADMIN_TAG'] }) }, + form: undefined + } + }); + + const readAll = document.querySelector( + 'input[name="permissions"][value="READ_ALL"]' + ) as HTMLInputElement; + const adminTag = document.querySelector( + 'input[name="permissions"][value="ADMIN_TAG"]' + ) as HTMLInputElement; + const writeAll = document.querySelector( + 'input[name="permissions"][value="WRITE_ALL"]' + ) as HTMLInputElement; + expect(readAll.checked).toBe(true); + expect(adminTag.checked).toBe(true); + expect(writeAll.checked).toBe(false); + }); + + it('shows the success banner when form.success is true', async () => { + render(AdminGroupEditPage, { + props: { data: { group: baseGroup() }, form: { success: true } } + }); + + await expect.element(page.getByText('Gruppe gespeichert.')).toBeVisible(); + }); + + it('shows the error banner when form.error is set', async () => { + render(AdminGroupEditPage, { + props: { + data: { group: baseGroup() }, + form: { error: 'Name darf nicht leer sein.' } + } + }); + + await expect.element(page.getByText('Name darf nicht leer sein.')).toBeVisible(); + }); + + it('renders the cancel link to /admin/groups', async () => { + render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } }); + + const links = document.querySelectorAll('a[href="/admin/groups"]'); + expect(links.length).toBeGreaterThan(0); + }); + + it('renders the delete and save buttons', async () => { + render(AdminGroupEditPage, { props: { data: { group: baseGroup() }, form: undefined } }); + + await expect.element(page.getByRole('button', { name: /löschen/i })).toBeVisible(); + await expect.element(page.getByRole('button', { name: /speichern/i })).toBeVisible(); + }); +});