this is my first post — I'm new to both Stack Overflow and SvelteKit. I'm trying to test a Svelte 5 Navbar component that conditionally shows links/buttons based on:
page.data.user — if the user is logged in
page.url.pathname — to hide certain links on specific routes
This works fine in the browser, but I can't figure out how to mock page in unit tests using Vitest + Testing Library.
Navbar.svelte
<script lang="ts">
import { page } from '$app/state';
import { goto, invalidateAll } from '$app/navigation';
let user = $state(page.data.user);
let currentPath = $state(page.url.pathname || '');
$effect(() => {
user = page.data.user;
currentPath = page.url.pathname || '';
invalidateAll();
});
async function handleLogout() {
try {
const formData = new FormData();
const response = await fetch('/logout', {
method: 'POST',
body: formData
});
if (response.ok) {
await goto('/');
}
} catch (error) {
console.error('Logout error:', error);
}
}
</script>
<nav
class="fixed top-0 right-0 left-0 z-50 flex h-16 items-center border-b border-gray-200 bg-white px-6 font-serif"
>
<!-- Left -->
<div class="flex-1">
{#if !user && !['/register', '/login', '/search'].includes(currentPath)}
<a href="/register">
<button class="rounded border border-gray-300 px-4 py-2 text-gray-700 hover:bg-gray-50">
Register
</button>
</a>
{/if}
</div>
<!-- Right -->
<div class="flex flex-1 items-center justify-end">
{#if user}
<button
onclick={handleLogout}
class="ml-4 rounded border border-gray-300 px-4 py-2 text-gray-700 hover:bg-gray-50"
>
Logout
</button>
{:else if !['/register', '/login', '/search'].includes(currentPath)}
<a href="/login" class="text-gray-700 hover:text-gray-900">Sign in</a>
{/if}
</div>
</nav>
Navbar.svelte.test.ts
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/svelte';
import Navbar from './Navbar.svelte';
vi.mock('$app/navigation', () => ({
goto: vi.fn(),
invalidateAll: vi.fn(),
}));
// I need help mocking $app/state.page here
describe('navigation bar', () => {
it('shows logout button when user is logged in', async () => {
render(Navbar);
expect(screen.getByRole('button', { name: /logout/i })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /register/i })).not.toBeInTheDocument();
expect(screen.queryByRole('link', { name: /sign in/i })).not.toBeInTheDocument();
});
});
What I need help with:
How can I mock the page store ($app/state.page) so I can, for example, simulate:
page.data.user = { name: 'Alex' }
page.url.pathname = '/search'
Tech stack:
SvelteKit 2.17.2
Svelte 5.20.2
Vitest 3.0.0
@testing-library/svelte 5.2.7
I have no clue where to start.
vi.mock()should work fine. If it doesn't, describe in detail the problems when you attempt this.