121 lines
4.4 KiB
TypeScript
121 lines
4.4 KiB
TypeScript
import { afterEach, beforeEach, describe, it, expect, vi } from 'vitest';
|
|
import { cleanup, render } from 'vitest-browser-svelte';
|
|
import { page } from 'vitest/browser';
|
|
import GroupsListPanel from './GroupsListPanel.svelte';
|
|
|
|
vi.mock('$app/state', () => ({
|
|
page: { url: { pathname: '/admin/groups/g1' } }
|
|
}));
|
|
|
|
afterEach(cleanup);
|
|
|
|
const groups = [
|
|
{ id: 'g1', name: 'Administrators', permissions: ['ADMIN', 'WRITE_ALL'] },
|
|
{ id: 'g2', name: 'Editors', permissions: ['WRITE_ALL'] },
|
|
{ id: 'g3', name: 'Readers', permissions: [] }
|
|
];
|
|
|
|
describe('GroupsListPanel — header', () => {
|
|
it('renders the panel title', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect.element(page.getByText(/Alle Gruppen/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders a new-group link pointing to /admin/groups/new', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect
|
|
.element(page.getByRole('link', { name: /neue gruppe/i }))
|
|
.toHaveAttribute('href', '/admin/groups/new');
|
|
});
|
|
});
|
|
|
|
describe('GroupsListPanel — group items', () => {
|
|
it('renders each group name', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect.element(page.getByRole('link', { name: /administrators/i })).toBeInTheDocument();
|
|
await expect.element(page.getByRole('link', { name: /editors/i })).toBeInTheDocument();
|
|
});
|
|
|
|
it('each group links to /admin/groups/[id]', async () => {
|
|
const { container } = render(GroupsListPanel, { groups });
|
|
const links = container.querySelectorAll<HTMLAnchorElement>('a[href^="/admin/groups/g"]');
|
|
expect(links.length).toBe(3);
|
|
expect(links[0].getAttribute('href')).toBe('/admin/groups/g1');
|
|
});
|
|
|
|
it('shows permission count as subtitle', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
// Administrators has 2 permissions
|
|
await expect.element(page.getByText(/2 Berechtigungen/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows "no permissions" for a group with zero permissions', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect.element(page.getByText(/0 Berechtigungen/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('GroupsListPanel — active state', () => {
|
|
it('marks the active group link with aria-current=page', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect
|
|
.element(page.getByRole('link', { name: /administrators/i }))
|
|
.toHaveAttribute('aria-current', 'page');
|
|
});
|
|
|
|
it('does not mark inactive group links with aria-current', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect
|
|
.element(page.getByRole('link', { name: /editors/i }))
|
|
.not.toHaveAttribute('aria-current');
|
|
});
|
|
});
|
|
|
|
describe('GroupsListPanel — empty state', () => {
|
|
it('shows empty state when groups array is empty', async () => {
|
|
render(GroupsListPanel, { groups: [] });
|
|
await expect.element(page.getByText(/keine gruppen/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
// ─── Collapse toggle ──────────────────────────────────────────────────────────
|
|
|
|
describe('GroupsListPanel — collapse toggle', () => {
|
|
beforeEach(() => localStorage.removeItem('admin_groups_list_collapsed'));
|
|
|
|
it('renders a collapse button with aria-label', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect
|
|
.element(page.getByRole('button', { name: /Liste einklappen/i }))
|
|
.toBeInTheDocument();
|
|
});
|
|
|
|
it('clicking collapse shows the expand handle', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
await expect
|
|
.element(page.getByRole('button', { name: /Liste einklappen/i }))
|
|
.toBeInTheDocument();
|
|
document.querySelector<HTMLButtonElement>('[aria-label="Liste einklappen"]')!.click();
|
|
await expect
|
|
.element(page.getByRole('button', { name: /Liste ausklappen/i }))
|
|
.toBeInTheDocument();
|
|
});
|
|
|
|
it('autocollapse prop starts the panel in collapsed state', async () => {
|
|
render(GroupsListPanel, { groups, autocollapse: true });
|
|
await expect
|
|
.element(page.getByRole('button', { name: /Liste ausklappen/i }))
|
|
.toBeInTheDocument();
|
|
});
|
|
|
|
it('persists collapse state using the groups-specific localStorage key', async () => {
|
|
render(GroupsListPanel, { groups });
|
|
const setSpy = vi.spyOn(Storage.prototype, 'setItem');
|
|
document.querySelector<HTMLButtonElement>('[aria-label="Liste einklappen"]')!.click();
|
|
await vi.waitFor(() =>
|
|
expect(setSpy).toHaveBeenCalledWith('admin_groups_list_collapsed', 'true')
|
|
);
|
|
setSpy.mockRestore();
|
|
});
|
|
});
|