Testing basics
A test is a small program that checks that your code works as intended. Tests are run after every change: if something breaks, you find out at once, not from visitors. For SvelteKit projects the standard tool is Vitest.
Adding Vitest
If you did not pick Vitest when creating the project, add it now:
npx sv add vitestThe utility installs the packages, adds settings to vite.config.js and adds a test:unit command to package.json. If it asks about kinds of tests, choose both unit and component tests.
Testing a plain function
Let us move the creation of a post address out of the form action into a separate function:
// src/lib/slugify.js
export function slugify(title) {
return title.trim().toLowerCase().replaceAll(' ', '-');
}The test goes next to it, with .test added to the name:
// src/lib/slugify.test.js
import { describe, expect, it } from 'vitest';
import { slugify } from './slugify.js';
describe('slugify', () => {
it('replaces spaces with hyphens', () => {
expect(slugify('Hello Svelte')).toBe('hello-svelte');
});
it('trims spaces at the edges', () => {
expect(slugify(' Runes ')).toBe('runes');
});
});describe groups tests, it describes one case, and expect(...).toBe(...) compares the result with the expected value.
Running
npm run test:unitVitest finds the *.test.js files, runs them and prints green marks next to passed tests in the terminal. The command keeps watching the files and reruns tests on save. To run the tests once and exit, use npx vitest run.
Testing a component
A component can be rendered into the test document with the mount function from the svelte package, and the resulting text can be checked. Take a counter that receives tasks as a prop:
<!-- src/lib/components/TodoCounter.svelte -->
<script>
let { todos } = $props();
let remaining = $derived(todos.filter((t) => !t.done).length);
</script>
<span>Left: {remaining}</span>// src/lib/components/TodoCounter.svelte.test.js
import { mount, unmount } from 'svelte';
import { expect, test } from 'vitest';
import TodoCounter from './TodoCounter.svelte';
test('counts unfinished tasks', () => {
const component = mount(TodoCounter, {
target: document.body,
props: {
todos: [
{ id: 1, text: 'Buy bread', done: false },
{ id: 2, text: 'Call Oleg', done: true }
]
}
});
expect(document.body.textContent).toContain('Left: 1');
unmount(component);
});The test passes if the text "Left: 1" appears on the "page". The .svelte.test.js ending tells the settings created by sv that the test needs a browser document.
End-to-end tests
To check the whole site — open a page, fill in a form, click a button — use end-to-end tests in a real browser. There is an add-on for them: npx sv add playwright.
Common mistake
Writing a component test in a file with the plain .test.js ending. In the sv settings such tests run in a Node.js environment without a DOM, and the test fails with document is not defined. Name tests that render components *.svelte.test.js.