From 30ea1f0dcf77d1bce269eec39553c776ab7bd72b Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 20 Apr 2026 22:36:41 +0200 Subject: [PATCH] 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) --- .../src/lib/components/EnrichmentBlock.svelte | 4 ++- .../components/EnrichmentBlock.svelte.spec.ts | 34 +++++++++++++++++-- .../components/__mocks__/navigatingStore.ts | 3 ++ 3 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 frontend/src/lib/components/__mocks__/navigatingStore.ts diff --git a/frontend/src/lib/components/EnrichmentBlock.svelte b/frontend/src/lib/components/EnrichmentBlock.svelte index 2743329f..a4327cf3 100644 --- a/frontend/src/lib/components/EnrichmentBlock.svelte +++ b/frontend/src/lib/components/EnrichmentBlock.svelte @@ -31,8 +31,10 @@ const showBlock = $derived(topDocs.length > 0 || bannerCount > 0 || showSkeleton {:else if showSkeleton} {/if} diff --git a/frontend/src/lib/components/EnrichmentBlock.svelte.spec.ts b/frontend/src/lib/components/EnrichmentBlock.svelte.spec.ts index be187cf5..ac5167d1 100644 --- a/frontend/src/lib/components/EnrichmentBlock.svelte.spec.ts +++ b/frontend/src/lib/components/EnrichmentBlock.svelte.spec.ts @@ -2,14 +2,20 @@ 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 { writable } = await import('svelte/store'); - return { navigating: writable(null) }; + const mod = await import('./__mocks__/navigatingStore'); + return { navigating: mod.navigatingStore }; }); -afterEach(cleanup); +afterEach(() => { + cleanup(); + navigatingStore.set(null); +}); type Doc = { id: string; title: string; uploadedAt: string }; @@ -58,4 +64,26 @@ describe('EnrichmentBlock', () => { 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(); + }); }); diff --git a/frontend/src/lib/components/__mocks__/navigatingStore.ts b/frontend/src/lib/components/__mocks__/navigatingStore.ts new file mode 100644 index 00000000..932122e4 --- /dev/null +++ b/frontend/src/lib/components/__mocks__/navigatingStore.ts @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const navigatingStore = writable(null);