I have created a skeleton project using Sveltekit. I would like to create unit tests for three different files. One of the first files is the index.js
under the src/lib
folder:
export function add(a, b) {
return a + b;
}
The other two files are a Svelte component. The home page is in the src/routes/+page.svelte
file:
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
The about page is in the src/routes/about/+page.svelte
file:
<script>
export let foo = 'bar';
</script>
<input type="text" bind:value={foo} />
<div>Hi {foo}!</div>
In the About page, there is a property that can be changed by an input field. How to pass values to the component during the unit test?
First, install the following libraries which are the prerequisites for testing Svelte components using Vitest:
npm install --save-dev @testing-library/svelte @testing-library/jest-dom jsdom
Next, create a vitest.config.js
config with the following content:
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [svelte()],
test: {
globals: true,
environment: 'jsdom',
}
});
Note: You can use different environments for testing, see the environment documentation for more detail.
Once everything is configured, you can begin testing the components. The most straightforward is the index.js
script. Create a src/test
folder and write the first unit test for the script file:
// index.test.js
import { describe, it, expect } from 'vitest';
import { add } from '../lib/index.js';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(add(1, 2)).toBe(3);
});
});
Make sure the imported path is correct and the functions to test are added. For the home page test, the jest-dom
library needs to be imported because of helper functions:
// home.test.js
import { describe, it, expect } from 'vitest';
import '@testing-library/jest-dom';
import { render } from '@testing-library/svelte';
import Home from '../routes/+page.svelte';
describe('Home route', () => {
it('renders the div with default value', () => {
const result = render(Home);
const headerText = result.getByText('Welcome to SvelteKit');
expect(headerText).toBeInTheDocument();
});
});
You see that Svelte's testing library is rendering the component. The render function has a lot of properties with which you find and get elements by ID, text, label, title, and so on.
Lastly, here is how to initialize the about component with the property:
// about.test.js
import { describe, it, expect } from 'vitest';
import '@testing-library/jest-dom';
import { render } from '@testing-library/svelte';
import About from '../routes/about/+page.svelte';
describe('About route', () => {
it('renders the div with default value', () => {
const { getByText } = render(About);
expect(getByText('Hi bar!')).toBeInTheDocument();
});
it('renders the div with property value', () => {
const { getByText } = render(About, { foo: 'foo' });
expect(getByText('Hi foo!')).toBeInTheDocument();
});
});
You can also use the getByRole
and the fireEvent
function to trigger the input field as well. After importing the fireEvent
function add the following testcase at the end of the test suite:
it('renders the div with input field', async () => {
const { getByText, getByRole } = render(About);
const inputField = getByRole('textbox');
await fireEvent.input(inputField, { target: { value: 'foobar' } });
expect(getByText('Hi foobar!')).toBeInTheDocument();
});