import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'; import { cleanup, render } from 'vitest-browser-svelte'; import { page as browserPage } from 'vitest/browser'; const mockPage = { url: new URL('http://localhost/admin/groups') }; vi.mock('$app/state', () => ({ get page() { return mockPage; } })); beforeEach(() => { localStorage.clear(); }); afterEach(cleanup); async function loadComponent() { return (await import('./GroupsListPanel.svelte')).default; } const baseGroups = [ { id: 'g1', name: 'Familie', permissions: ['READ_ALL'] }, { id: 'g2', name: 'Admins', permissions: ['ADMIN', 'WRITE_ALL'] } ]; describe('GroupsListPanel', () => { it('renders the expanded list with header by default', async () => { mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); await expect.element(browserPage.getByText('Alle Gruppen')).toBeVisible(); }); it('renders one row per group with permission count', async () => { mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); await expect.element(browserPage.getByText('Familie')).toBeVisible(); await expect.element(browserPage.getByText('Admins')).toBeVisible(); await expect.element(browserPage.getByText('1 Berechtigungen')).toBeVisible(); await expect.element(browserPage.getByText('2 Berechtigungen')).toBeVisible(); }); it('renders the empty placeholder when groups is empty', async () => { mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: [] } }); await expect.element(browserPage.getByText('Keine Gruppen vorhanden.')).toBeVisible(); }); it('renders the new-group link to /admin/groups/new', async () => { mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); await expect .element(browserPage.getByRole('link', { name: /neue gruppe/i })) .toHaveAttribute('href', '/admin/groups/new'); }); it('marks the active group with aria-current=page', async () => { mockPage.url = new URL('http://localhost/admin/groups/g2'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); const links = Array.from( document.querySelectorAll('a[href^="/admin/groups/"]') ) as HTMLAnchorElement[]; const adminsLink = links.find((a) => a.href.endsWith('/admin/groups/g2')); expect(adminsLink?.getAttribute('aria-current')).toBe('page'); }); it('renders collapsed view when autocollapse is true', async () => { mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups, autocollapse: true } }); await expect .element(browserPage.getByRole('button', { name: /liste ausklappen/i })) .toBeVisible(); }); it('honours the localStorage manual-collapse preference', async () => { localStorage.setItem('admin_groups_list_collapsed', 'true'); mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); await expect .element(browserPage.getByRole('button', { name: /liste ausklappen/i })) .toBeVisible(); }); it('expands the panel when the collapsed handle is clicked', async () => { localStorage.setItem('admin_groups_list_collapsed', 'true'); mockPage.url = new URL('http://localhost/admin/groups'); const Panel = await loadComponent(); render(Panel, { props: { groups: baseGroups } }); await browserPage.getByRole('button', { name: /liste ausklappen/i }).click(); await expect.element(browserPage.getByText('Alle Gruppen')).toBeVisible(); }); });