From 3891cb79b471b0653f3ec95d184f45c61318e029 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 10 May 2026 01:09:25 +0200 Subject: [PATCH] test(aktivitaeten): smoke-cover the page with mocked notification store Mounts the aktivitaeten page with mocks for the notification SSE singleton (init/destroy/markRead/markAllRead) and $app/state. Verifies heading renders, error state renders main element, empty state renders main, and a non-default filter renders without crashing. 4 tests covering the orchestration entry path. Refs #496. Co-Authored-By: Claude Sonnet 4.6 --- .../routes/aktivitaeten/page.svelte.test.ts | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 frontend/src/routes/aktivitaeten/page.svelte.test.ts diff --git a/frontend/src/routes/aktivitaeten/page.svelte.test.ts b/frontend/src/routes/aktivitaeten/page.svelte.test.ts new file mode 100644 index 00000000..c94ec176 --- /dev/null +++ b/frontend/src/routes/aktivitaeten/page.svelte.test.ts @@ -0,0 +1,81 @@ +import { describe, it, expect, vi, afterEach } from 'vitest'; +import { cleanup, render } from 'vitest-browser-svelte'; +import { page } from 'vitest/browser'; + +const mockNavigating = { type: null }; +const mockPage = { url: new URL('http://localhost/aktivitaeten') }; + +vi.mock('$app/state', () => ({ + get navigating() { + return mockNavigating; + }, + get page() { + return mockPage; + } +})); + +vi.mock('$app/navigation', () => ({ + beforeNavigate: () => {}, + afterNavigate: () => {}, + goto: vi.fn(), + invalidate: vi.fn(), + invalidateAll: vi.fn(), + preloadCode: vi.fn(), + preloadData: vi.fn(), + pushState: vi.fn(), + replaceState: vi.fn(), + disableScrollHandling: vi.fn(), + onNavigate: () => () => {} +})); + +vi.mock('$lib/notification/notifications.svelte', () => ({ + notificationStore: { + notifications: [], + init: vi.fn(), + destroy: vi.fn(), + markRead: vi.fn(), + markAllRead: vi.fn() + } +})); + +const { default: AktivitaetenPage } = await import('./+page.svelte'); + +afterEach(cleanup); + +const baseData = (overrides: Record = {}) => ({ + filter: 'alle' as const, + activityFeed: [], + unreadNotifications: [], + loadError: null, + ...overrides +}); + +describe('aktivitaeten page', () => { + it('renders the page heading', async () => { + render(AktivitaetenPage, { props: { data: baseData() } }); + + await expect.element(page.getByRole('heading', { name: /aktivitäten/i })).toBeVisible(); + }); + + it('renders the error card when loadError is "activity"', async () => { + render(AktivitaetenPage, { props: { data: baseData({ loadError: 'activity' }) } }); + + // ChronikErrorCard renders some retry mechanism + const main = document.querySelector('main'); + expect(main).not.toBeNull(); + }); + + it('renders the empty state when activityFeed is empty', async () => { + render(AktivitaetenPage, { props: { data: baseData() } }); + + const main = document.querySelector('main'); + expect(main).not.toBeNull(); + }); + + it('renders without crashing when filter is set to non-default value', async () => { + render(AktivitaetenPage, { props: { data: baseData({ filter: 'mentions' as const }) } }); + + const main = document.querySelector('main'); + expect(main).not.toBeNull(); + }); +});