test(document): cover TimelineControls and TimelineXAxis branches

TimelineControls: empty render when neither flag is set, reset button
gated on isZoomed, clear button gated on hasSelection, both-on, both
callback wirings.

TimelineXAxis: empty filled → no ticks, populated → ticks render,
omit-year branch when all buckets share a year, show-year branch
across multiple years, length-4 bucket-string fallback.

11 tests across two timeline primitives.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-09 21:48:15 +02:00
parent 79511ec9a7
commit 5dcb535555
2 changed files with 138 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import TimelineControls from './TimelineControls.svelte';
afterEach(cleanup);
describe('TimelineControls', () => {
it('renders neither button when not zoomed and no selection', async () => {
render(TimelineControls, {
props: {
isZoomed: false,
hasSelection: false,
onresetzoom: () => {},
onclearselection: () => {}
}
});
const buttons = document.querySelectorAll('button');
expect(buttons.length).toBe(0);
});
it('renders the reset-zoom button when isZoomed is true', async () => {
render(TimelineControls, {
props: {
isZoomed: true,
hasSelection: false,
onresetzoom: () => {},
onclearselection: () => {}
}
});
await expect.element(page.getByRole('button', { name: /zur übersicht/i })).toBeVisible();
});
it('renders the clear-selection button when hasSelection is true', async () => {
render(TimelineControls, {
props: {
isZoomed: false,
hasSelection: true,
onresetzoom: () => {},
onclearselection: () => {}
}
});
await expect.element(page.getByRole('button', { name: /auswahl zurücksetzen/i })).toBeVisible();
});
it('renders both buttons when both flags are true', async () => {
render(TimelineControls, {
props: {
isZoomed: true,
hasSelection: true,
onresetzoom: () => {},
onclearselection: () => {}
}
});
const buttons = document.querySelectorAll('button');
expect(buttons.length).toBe(2);
});
it('calls onresetzoom when the reset button is clicked', async () => {
const onresetzoom = vi.fn();
render(TimelineControls, {
props: { isZoomed: true, hasSelection: false, onresetzoom, onclearselection: () => {} }
});
await page.getByRole('button', { name: /zur übersicht/i }).click();
expect(onresetzoom).toHaveBeenCalledOnce();
});
it('calls onclearselection when the clear button is clicked', async () => {
const onclearselection = vi.fn();
render(TimelineControls, {
props: { isZoomed: false, hasSelection: true, onresetzoom: () => {}, onclearselection }
});
await page.getByRole('button', { name: /auswahl zurücksetzen/i }).click();
expect(onclearselection).toHaveBeenCalledOnce();
});
});

View File

@@ -0,0 +1,54 @@
import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import TimelineXAxis from './TimelineXAxis.svelte';
afterEach(cleanup);
const bucket = (month: string, count = 1) => ({ month, count });
describe('TimelineXAxis', () => {
it('renders no ticks when filled is empty', async () => {
render(TimelineXAxis, { props: { filled: [] } });
const ticks = document.querySelectorAll('[data-testid="timeline-x-tick"]');
expect(ticks.length).toBe(0);
});
it('renders tick marks when filled buckets are present', async () => {
const filled = Array.from({ length: 12 }, (_, i) =>
bucket(`1923-${String(i + 1).padStart(2, '0')}`)
);
render(TimelineXAxis, { props: { filled } });
const ticks = document.querySelectorAll('[data-testid="timeline-x-tick"]');
expect(ticks.length).toBeGreaterThan(0);
});
it('omits the year when all visible buckets share the same year', async () => {
const filled = Array.from({ length: 12 }, (_, i) =>
bucket(`1923-${String(i + 1).padStart(2, '0')}`)
);
render(TimelineXAxis, { props: { filled } });
const ticks = Array.from(document.querySelectorAll('[data-testid="timeline-x-tick"]'));
const allText = ticks.map((t) => t.textContent ?? '').join(' ');
expect(allText).not.toContain('1923');
});
it('shows the year when buckets span multiple years', async () => {
const filled = [bucket('1923-01'), bucket('1924-06'), bucket('1925-12')];
render(TimelineXAxis, { props: { filled } });
const ticks = Array.from(document.querySelectorAll('[data-testid="timeline-x-tick"]'));
const allText = ticks.map((t) => t.textContent ?? '').join(' ');
expect(allText).toMatch(/19\d{2}/);
});
it('handles single-year (length-4) bucket month strings without omitting the year', async () => {
const filled = [bucket('1923'), bucket('1924')];
render(TimelineXAxis, { props: { filled } });
const ticks = document.querySelectorAll('[data-testid="timeline-x-tick"]');
expect(ticks.length).toBeGreaterThan(0);
});
});