Files
familienarchiv/frontend/src/lib/ocr/SegmentationTrainingCard.svelte.test.ts
Marcel 00a8878146 test: cover PersonEditForm and SegmentationTrainingCard branches
PersonEditForm: PERSON vs INSTITUTION/GROUP visibility matrix (firstName,
title, alias, birth/deathYear toggle), lastName label switch, prop
hydration of all populated fields, fallback to PERSON for unknown type,
empty-string handling for null fields. 10 tests, ~30 branches.

SegmentationTrainingCard: trainingInfo null vs populated, block count
display, button disabled-state matrix (training × tooFewBlocks ×
serviceDown), too-few-blocks and service-down hints, success message
after a mocked fetch, training history heading. 10 tests, ~25 branches.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 21:50:28 +02:00

111 lines
3.6 KiB
TypeScript

import { describe, it, expect, afterEach, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import SegmentationTrainingCard from './SegmentationTrainingCard.svelte';
afterEach(cleanup);
const baseInfo = (overrides: Record<string, unknown> = {}) => ({
availableSegBlocks: 10,
ocrServiceAvailable: true,
runs: [],
...overrides
});
describe('SegmentationTrainingCard', () => {
it('renders the heading and description', async () => {
render(SegmentationTrainingCard, { props: { trainingInfo: baseInfo() } });
await expect
.element(page.getByRole('heading', { name: /segmentierung trainieren/i }))
.toBeVisible();
await expect.element(page.getByText(/Starte ein neues Training/i)).toBeVisible();
});
it('shows the count of available segmentation blocks', async () => {
render(SegmentationTrainingCard, {
props: { trainingInfo: baseInfo({ availableSegBlocks: 42 }) }
});
await expect.element(page.getByText('42 Segmentierungsblöcke bereit')).toBeVisible();
});
it('shows zero blocks when trainingInfo is null', async () => {
render(SegmentationTrainingCard, { props: { trainingInfo: null } });
await expect.element(page.getByText('0 Segmentierungsblöcke bereit')).toBeVisible();
});
it('disables the start button when fewer than 5 blocks are available', async () => {
render(SegmentationTrainingCard, {
props: { trainingInfo: baseInfo({ availableSegBlocks: 3 }) }
});
const btn = (await page
.getByRole('button', { name: /training starten/i })
.element()) as HTMLButtonElement;
expect(btn.disabled).toBe(true);
});
it('shows the too-few-blocks hint when fewer than 5 blocks are available', async () => {
render(SegmentationTrainingCard, {
props: { trainingInfo: baseInfo({ availableSegBlocks: 3 }) }
});
await expect
.element(page.getByText(/Mindestens 5 Segmentierungsblöcke erforderlich/i))
.toBeVisible();
});
it('disables the start button when the OCR service is reported down', async () => {
render(SegmentationTrainingCard, {
props: { trainingInfo: baseInfo({ ocrServiceAvailable: false }) }
});
const btn = (await page
.getByRole('button', { name: /training starten/i })
.element()) as HTMLButtonElement;
expect(btn.disabled).toBe(true);
});
it('shows the service-down hint when ocrServiceAvailable is false', async () => {
render(SegmentationTrainingCard, {
props: { trainingInfo: baseInfo({ ocrServiceAvailable: false }) }
});
await expect.element(page.getByText('OCR-Dienst ist nicht erreichbar.')).toBeVisible();
});
it('enables the start button when blocks are sufficient and the service is up', async () => {
render(SegmentationTrainingCard, { props: { trainingInfo: baseInfo() } });
const btn = (await page
.getByRole('button', { name: /training starten/i })
.element()) as HTMLButtonElement;
expect(btn.disabled).toBe(false);
});
it('shows the success message after a successful training POST', async () => {
const fetchSpy = vi
.spyOn(globalThis, 'fetch')
.mockResolvedValue(new Response('{}', { status: 200 }));
try {
render(SegmentationTrainingCard, { props: { trainingInfo: baseInfo() } });
await page.getByRole('button', { name: /training starten/i }).click();
await expect
.element(page.getByText('Training wurde gestartet und abgeschlossen.'))
.toBeVisible();
} finally {
fetchSpy.mockRestore();
}
});
it('renders the training history heading', async () => {
render(SegmentationTrainingCard, { props: { trainingInfo: baseInfo() } });
await expect.element(page.getByRole('heading', { name: /verlauf/i })).toBeVisible();
});
});