Testing Svelte Applications with Vitest
Testing is a crucial aspect of delivering reliable Svelte applications. With Vitest, we have a powerful testing framework that integrates seamlessly with the Svelte ecosystem. Let’s explore how to implement effective testing strategies that ensure your applications remain robust and maintainable.
Why Vitest for Svelte Testing?
Vitest stands out as the optimal choice for testing Svelte applications for several reasons:
- Native ESM support
- SvelteKit integration out of the box
- Exceptional performance through parallel test execution
- Compatible with Jest’s expect syntax
- Watch mode with smart file tracking
Setting Up Vitest in Your Svelte Project
The setup process is straightforward. If you’re using SvelteKit, Vitest is included by default. For other Svelte projects, you’ll need to install it:
pnpm add -D vitest @testing-library/svelte
Configure Vitest in your vite.config.ts
:
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte({ hot: !process.env.VITEST })],
test: {
include: ['src/**/*.{test,spec}.{js,ts}'],
environment: 'jsdom',
globals: true,
},
});
Writing Your First Test
Let’s start with a basic component test. Consider a simple counter component:
// src/lib/components/Counter.test.ts
import { describe, it, expect } from 'vitest';
import { render, fireEvent } from '@testing-library/svelte';
import Counter from './Counter.svelte';
describe('Counter', () => {
it('increments value on button click', async () => {
const { getByText } = render(Counter);
const button = getByText('Increment');
const value = getByText('0');
await fireEvent.click(button);
expect(getByText('1')).toBeTruthy();
});
});
Testing Server Routes
For SvelteKit applications, testing server routes is crucial. Here’s how to test a typical server endpoint:
// src/routes/api/data/+server.test.ts
import { describe, it, expect } from 'vitest';
import { GET } from './+server';
describe('GET handler', () => {
it('returns correct data structure', async () => {
const response = await GET();
const data = await response.json();
expect(response.status).toBe(200);
expect(data).toHaveProperty('items');
});
});
Integration Testing Best Practices
When writing integration tests, focus on user interactions and business logic:
// src/routes/todos/+page.server.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { POST } from './+server';
describe('Todo API', () => {
beforeEach(() => {
// Reset test database or state
});
it('creates new todo item', async () => {
const formData = new FormData();
formData.append('title', 'Test Todo');
const response = await POST({
request: new Request('', {
method: 'POST',
body: formData,
}),
});
const data = await response.json();
expect(data.title).toBe('Test Todo');
expect(response.status).toBe(201);
});
});
Testing Loading States
Testing loading states ensures a smooth user experience:
// src/routes/data/+page.test.ts
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/svelte';
import Page from './+page.svelte';
describe('Data Page', () => {
it('shows loading state', () => {
render(Page, { props: { loading: true } });
expect(screen.getByText('Loading...')).toBeTruthy();
});
});
Mocking External Dependencies
Effective testing often requires mocking external dependencies:
// src/lib/api.test.ts
import { describe, it, expect, vi } from 'vitest';
import { fetch_data } from './api';
vi.mock('$app/environment', () => ({
browser: true,
}));
describe('API', () => {
it('handles network errors gracefully', async () => {
vi.spyOn(global, 'fetch').mockRejectedValueOnce(
new Error('Network error'),
);
const result = await fetch_data();
expect(result.error).toBe('Failed to fetch data');
});
});
Measuring Test Coverage
Vitest provides built-in coverage reporting. Add this to your vite.config.ts
:
test: {
coverage: {
reporter: ['text', 'json', 'html'],
exclude: ['node_modules/', 'src/**/*.{test,spec}.{js,ts}']
}
}
Run coverage reports with:
pnpm vitest run --coverage
Conclusion
Implementing a robust testing strategy with Vitest in your Svelte applications leads to:
- Reduced bugs in production
- Confident code refactoring
- Improved development velocity
- Better documentation through tests
- Enhanced team collaboration
By following these testing patterns, you’ll build more reliable applications while maintaining development efficiency. Remember, tests are not just about catching bugs—they’re about building confidence in your codebase and enabling faster, safer iterations.