Why Your Svelte 5 Tests Should Run in Real Browsers
I first heard about vitest-browser-svelte at Svelte Summit from
Dominik G, one of the core maintainers of SvelteKit and Vite. The pitch
was simple: test Svelte components in actual browsers instead of
simulated environments like JSDOM.
After migrating several production codebases, I’m convinced this is how all Svelte teams should test.
The Problem with JSDOM
JSDOM simulates a browser environment in Node.js. It’s fast and convenient, but:
- No real layout -
getBoundingClientRect()returns zeros - No real events - Synthetic events don’t bubble like real ones
- No real CSS - Media queries, animations, transitions don’t work
- Missing APIs - ResizeObserver, IntersectionObserver need polyfills
Your tests pass, but they’re testing a simulation, not reality.
What Changes with Browser Mode
Vitest’s browser mode runs your tests in actual Chromium, Firefox, or WebKit via Playwright:
// vitest.config.ts
export default defineConfig({
plugins: [sveltekit()],
test: {
browser: {
enabled: true,
provider: 'playwright',
instances: [{ browser: 'chromium' }],
},
},
}); Your component renders in a real browser. Events fire through the real DOM. CSS actually applies.
The vitest-browser-svelte API
The API is clean and familiar:
import { render, screen } from 'vitest-browser-svelte';
import { expect, test } from 'vitest';
import Counter from './Counter.svelte';
test('increments count on click', async () => {
render(Counter, { props: { initial: 0 } });
const button = screen.getByRole('button');
await button.click();
await expect.element(button).toHaveTextContent('Count: 1');
}); Key differences from @testing-library/svelte:
- Locators, not elements -
screen.getByRole()returns a locator - Async assertions -
expect.element()with built-in waiting - Real clicks -
await button.click()fires real browser events
Migration Path
For teams on @testing-library/svelte:
- Install:
vitest-browser-svelte,@vitest/browser,playwright - Update vitest config for browser mode
- Replace imports:
vitest-browser-svelteinstead of@testing-library/svelte - Update assertions to async pattern
Most tests migrate with minimal changes. The ones that break usually reveal real bugs your JSDOM tests were missing.
When to Use This
Browser mode is ideal for:
- Component libraries - Test real rendering and interactions
- Complex forms - Validation, focus management, accessibility
- Animations/transitions - Actually test CSS behaviors
- Cross-browser testing - Run same tests in multiple browsers
Keep unit tests in Node for pure logic. Use browser mode for anything touching the DOM.
Team Benefits
For development teams:
- Confidence - Tests verify real browser behavior
- Fewer production bugs - Catch issues JSDOM misses
- Better DX - Playwright’s debugging tools are excellent
- Future-proof - This is where the ecosystem is heading
Need Help Migrating?
I’ve set up Vitest browser mode testing for multiple SvelteKit teams. If you’re stuck on legacy testing patterns or want to modernize your test infrastructure - let’s talk.