Files
familienarchiv/frontend/src/lib/components/EnrichmentBlock.svelte.spec.ts
Marcel 30ea1f0dcf test(dashboard): exercise the EnrichmentBlock skeleton branch
Hoists the $navigating store into a shared __mocks__ module so tests can
drive it through real transitions. Adds two specs covering (a) skeleton
visible while $navigating && topDocs empty and (b) skeleton hidden when
topDocs is non-empty. Also sets aria-busy="true" on the skeleton so
screen readers announce the loading state (Leonie's a11y suggestion).

Addresses Sara's and Felix's review concern that the skeleton branch was
dead code in the test world.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 22:36:41 +02:00

90 lines
2.7 KiB
TypeScript

import { describe, it, expect, afterEach, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
// The store must live in a separate module because vi.mock factories are
// hoisted and cannot reference top-level variables defined in this file.
import { navigatingStore } from './__mocks__/navigatingStore';
import EnrichmentBlock from './EnrichmentBlock.svelte';
vi.mock('$app/stores', async () => {
const mod = await import('./__mocks__/navigatingStore');
return { navigating: mod.navigatingStore };
});
afterEach(() => {
cleanup();
navigatingStore.set(null);
});
type Doc = { id: string; title: string; uploadedAt: string };
function doc(id: string, title = 'Doc'): Doc {
return { id, title, uploadedAt: '2026-04-20T12:00:00' };
}
describe('EnrichmentBlock', () => {
it('renders nothing when topDocs is empty and banner count is 0', async () => {
render(EnrichmentBlock, {
topDocs: [],
totalCount: 0,
bannerCount: 0,
onBannerClose: vi.fn()
});
await expect.element(page.getByTestId('enrichment-block')).not.toBeInTheDocument();
});
it('renders the list component when topDocs is non-empty', async () => {
render(EnrichmentBlock, {
topDocs: [doc('d1')],
totalCount: 1,
bannerCount: 0,
onBannerClose: vi.fn()
});
await expect.element(page.getByTestId('dashboard-needs-metadata')).toBeInTheDocument();
});
it('renders the banner when bannerCount > 0', async () => {
render(EnrichmentBlock, {
topDocs: [],
totalCount: 0,
bannerCount: 3,
onBannerClose: vi.fn()
});
await expect.element(page.getByRole('status')).toBeInTheDocument();
});
it('composes banner + list when both are present', async () => {
render(EnrichmentBlock, {
topDocs: [doc('d1')],
totalCount: 1,
bannerCount: 2,
onBannerClose: vi.fn()
});
await expect.element(page.getByRole('status')).toBeInTheDocument();
await expect.element(page.getByTestId('dashboard-needs-metadata')).toBeInTheDocument();
});
it('renders the skeleton when $navigating is active and topDocs is empty', async () => {
navigatingStore.set({ type: 'link' });
render(EnrichmentBlock, {
topDocs: [],
totalCount: 0,
bannerCount: 0,
onBannerClose: vi.fn()
});
await expect.element(page.getByTestId('enrichment-block-skeleton')).toBeInTheDocument();
});
it('does not render the skeleton when topDocs is non-empty even during $navigating', async () => {
navigatingStore.set({ type: 'link' });
render(EnrichmentBlock, {
topDocs: [doc('d1')],
totalCount: 1,
bannerCount: 0,
onBannerClose: vi.fn()
});
await expect.element(page.getByTestId('enrichment-block-skeleton')).not.toBeInTheDocument();
});
});