test(mocks): add shared $app/navigation mock with simulateNavigate
Exports the standard nav functions as vi.fn() and a beforeNavigate that captures the registered callback. The exported simulateNavigate(href) helper fires that callback and returns the cancel spy — the whole capture-and-fire pattern lives in the shared module, not the raw callback. An embedded beforeEach clears the captured callback and the mock call histories before every test. Part of #560. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
62
frontend/src/__mocks__/$app/navigation.ts
Normal file
62
frontend/src/__mocks__/$app/navigation.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
// Shared browser-test mock body for the SvelteKit `$app/navigation` virtual module.
|
||||
//
|
||||
// Imported into a sync vi.mock factory via the $mocks alias:
|
||||
// import * as navMock from '$mocks/$app/navigation';
|
||||
// vi.mock('$app/navigation', () => ({ ...navMock }));
|
||||
//
|
||||
// All navigation functions are vi.fn() stubs. `beforeNavigate` additionally
|
||||
// captures the registered callback so a test can drive it through the exported
|
||||
// `simulateNavigate(href)` helper — the whole capture-and-fire pattern lives
|
||||
// here, not the raw callback. The embedded `beforeEach` clears the captured
|
||||
// callback and the mock call histories before every test, so isolation is
|
||||
// structural. See ADR-012.
|
||||
|
||||
import { beforeEach, vi } from 'vitest';
|
||||
|
||||
type BeforeNavigateCallback = (nav: {
|
||||
cancel: () => void;
|
||||
to: { url: { href: string } } | null;
|
||||
}) => void;
|
||||
|
||||
let _registeredBeforeNavigate: BeforeNavigateCallback | null = null;
|
||||
|
||||
export const goto = vi.fn();
|
||||
export const invalidate = vi.fn();
|
||||
export const invalidateAll = vi.fn();
|
||||
export const beforeNavigate = vi.fn((fn: BeforeNavigateCallback) => {
|
||||
_registeredBeforeNavigate = fn;
|
||||
});
|
||||
export const afterNavigate = vi.fn();
|
||||
export const preloadCode = vi.fn();
|
||||
export const preloadData = vi.fn();
|
||||
export const pushState = vi.fn();
|
||||
export const replaceState = vi.fn();
|
||||
export const disableScrollHandling = vi.fn();
|
||||
export const onNavigate = vi.fn();
|
||||
|
||||
const _navMocks = [
|
||||
goto,
|
||||
invalidate,
|
||||
invalidateAll,
|
||||
beforeNavigate,
|
||||
afterNavigate,
|
||||
preloadCode,
|
||||
preloadData,
|
||||
pushState,
|
||||
replaceState,
|
||||
disableScrollHandling,
|
||||
onNavigate
|
||||
];
|
||||
|
||||
// Fire the captured beforeNavigate callback as if navigating to `href`.
|
||||
// Returns the cancel spy so the test can assert whether navigation was blocked.
|
||||
export function simulateNavigate(href: string | null = '/somewhere'): ReturnType<typeof vi.fn> {
|
||||
const cancel = vi.fn();
|
||||
_registeredBeforeNavigate?.({ cancel, to: href ? { url: { href } } : null });
|
||||
return cancel;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
_registeredBeforeNavigate = null;
|
||||
_navMocks.forEach((mock) => mock.mockClear());
|
||||
});
|
||||
Reference in New Issue
Block a user