test: cover ScriptTypeSelect, SinglePersonHintBar, UserGroupsSection
ScriptTypeSelect: option list, placeholder disabled, value initialisation, disabled prop propagation. SinglePersonHintBar: hasDateFilter false vs true branches, sortDir DESC vs ASC label switch, year-range with only fromDate fallback. UserGroupsSection: per-group checkbox rendering, label visibility, selectedGroupIds preselection, empty groups list, default empty selection. 15 tests across three small primitives. Refs #496. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
43
frontend/src/lib/document/ScriptTypeSelect.svelte.test.ts
Normal file
43
frontend/src/lib/document/ScriptTypeSelect.svelte.test.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { describe, it, expect, afterEach } from 'vitest';
|
||||||
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
|
import { page } from 'vitest/browser';
|
||||||
|
import ScriptTypeSelect from './ScriptTypeSelect.svelte';
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
describe('ScriptTypeSelect', () => {
|
||||||
|
it('renders the label and select', async () => {
|
||||||
|
render(ScriptTypeSelect, { props: { value: '' } });
|
||||||
|
|
||||||
|
await expect.element(page.getByLabelText(/schrifttyp/i)).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders all four option values', async () => {
|
||||||
|
render(ScriptTypeSelect, { props: { value: '' } });
|
||||||
|
|
||||||
|
const options = document.querySelectorAll('option');
|
||||||
|
const values = Array.from(options).map((o) => (o as HTMLOptionElement).value);
|
||||||
|
expect(values).toEqual(['', 'TYPEWRITER', 'HANDWRITING_LATIN', 'HANDWRITING_KURRENT']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('marks the placeholder option as disabled', async () => {
|
||||||
|
render(ScriptTypeSelect, { props: { value: '' } });
|
||||||
|
|
||||||
|
const placeholder = document.querySelector('option[value=""]') as HTMLOptionElement;
|
||||||
|
expect(placeholder.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initialises the select with the supplied value', async () => {
|
||||||
|
render(ScriptTypeSelect, { props: { value: 'TYPEWRITER' } });
|
||||||
|
|
||||||
|
const select = (await page.getByRole('combobox').element()) as HTMLSelectElement;
|
||||||
|
expect(select.value).toBe('TYPEWRITER');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables the select when the disabled prop is true', async () => {
|
||||||
|
render(ScriptTypeSelect, { props: { value: '', disabled: true } });
|
||||||
|
|
||||||
|
const select = (await page.getByRole('combobox').element()) as HTMLSelectElement;
|
||||||
|
expect(select.disabled).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
54
frontend/src/lib/user/UserGroupsSection.svelte.test.ts
Normal file
54
frontend/src/lib/user/UserGroupsSection.svelte.test.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { describe, it, expect, afterEach } from 'vitest';
|
||||||
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
|
import UserGroupsSection from './UserGroupsSection.svelte';
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
const groups = [
|
||||||
|
{ id: 'g1', name: 'Familie' },
|
||||||
|
{ id: 'g2', name: 'Admins' },
|
||||||
|
{ id: 'g3', name: 'Lesetransport' }
|
||||||
|
];
|
||||||
|
|
||||||
|
describe('UserGroupsSection', () => {
|
||||||
|
it('renders one checkbox per group', async () => {
|
||||||
|
render(UserGroupsSection, { props: { groups } });
|
||||||
|
|
||||||
|
const checkboxes = document.querySelectorAll('input[name="groupIds"]');
|
||||||
|
expect(checkboxes.length).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders each group label', async () => {
|
||||||
|
render(UserGroupsSection, { props: { groups } });
|
||||||
|
|
||||||
|
expect(document.body.textContent).toContain('Familie');
|
||||||
|
expect(document.body.textContent).toContain('Admins');
|
||||||
|
expect(document.body.textContent).toContain('Lesetransport');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('preselects checkboxes for ids in selectedGroupIds', async () => {
|
||||||
|
render(UserGroupsSection, { props: { groups, selectedGroupIds: ['g1', 'g3'] } });
|
||||||
|
|
||||||
|
const checkboxes = Array.from(
|
||||||
|
document.querySelectorAll('input[name="groupIds"]')
|
||||||
|
) as HTMLInputElement[];
|
||||||
|
const checkedValues = checkboxes.filter((c) => c.checked).map((c) => c.value);
|
||||||
|
expect(checkedValues.sort()).toEqual(['g1', 'g3']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders nothing when groups is empty', async () => {
|
||||||
|
render(UserGroupsSection, { props: { groups: [] } });
|
||||||
|
|
||||||
|
const checkboxes = document.querySelectorAll('input[name="groupIds"]');
|
||||||
|
expect(checkboxes.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles a missing selectedGroupIds prop by defaulting to none selected', async () => {
|
||||||
|
render(UserGroupsSection, { props: { groups } });
|
||||||
|
|
||||||
|
const checkboxes = Array.from(
|
||||||
|
document.querySelectorAll('input[name="groupIds"]')
|
||||||
|
) as HTMLInputElement[];
|
||||||
|
expect(checkboxes.every((c) => !c.checked)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { describe, it, expect, afterEach } from 'vitest';
|
||||||
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
|
import { page } from 'vitest/browser';
|
||||||
|
import SinglePersonHintBar from './SinglePersonHintBar.svelte';
|
||||||
|
|
||||||
|
afterEach(cleanup);
|
||||||
|
|
||||||
|
describe('SinglePersonHintBar', () => {
|
||||||
|
it('renders the no-filter prompt when neither fromDate nor toDate is supplied', async () => {
|
||||||
|
render(SinglePersonHintBar, { props: { senderName: 'Anna Schmidt' } });
|
||||||
|
|
||||||
|
await expect.element(page.getByText('Anna Schmidt')).toBeVisible();
|
||||||
|
await expect.element(page.getByText(/wähle einen korrespondenten/i)).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the year range and sort label when fromDate is supplied', async () => {
|
||||||
|
render(SinglePersonHintBar, {
|
||||||
|
props: {
|
||||||
|
senderName: 'Anna Schmidt',
|
||||||
|
fromDate: '1923-01-01',
|
||||||
|
toDate: '1925-12-31',
|
||||||
|
sortDir: 'DESC'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect.element(page.getByText('1923–1925')).toBeVisible();
|
||||||
|
await expect.element(page.getByText('Neueste')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the "Älteste" label when sortDir is ASC', async () => {
|
||||||
|
render(SinglePersonHintBar, {
|
||||||
|
props: { senderName: 'Anna Schmidt', fromDate: '1923-01-01', sortDir: 'ASC' }
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect.element(page.getByText('Älteste')).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hides the no-filter prompt when fromDate alone is set', async () => {
|
||||||
|
render(SinglePersonHintBar, {
|
||||||
|
props: { senderName: 'Anna Schmidt', fromDate: '1923-01-01' }
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect.element(page.getByText(/wähle einen korrespondenten/i)).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows year range using only fromYear when toDate is empty', async () => {
|
||||||
|
render(SinglePersonHintBar, {
|
||||||
|
props: { senderName: 'Anna Schmidt', fromDate: '1923-01-01' }
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect.element(page.getByText('1923–')).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user