I love writing with Svelte. It’s pretty simple to learn and you can build quite complex and robust behaviour really quickly. The support and documentation is also awesome: being able to create a basic project with degit
means you can be productive even faster.
One thing that’s missing from the template project is a starter test suite. This means I’ve never really tried to write any automated tests against my Svelte code. I’ve definitely written large apps that could have done with this level of support. I decided to look into how to do it.
Turns out that it’s actually reasonably easy to get testing set up, although not without its challenges. This brief guide will take you through what worked for me!
Test runner
Firstly, we need to pick a test runner. Jest is a great choice because it's simple to get running and includes a bunch of useful utilities like mocks and assertions.
npm install --save-dev jest
You'll need to add a couple of extra scripts into your package.json
. These scripts assume that your source files (and the location of your tests) will be in the src
folder.
"scripts": {
...
"test": "jest src",
"test:watch": "npm run test -- --watch"
}
You should now be able to run the test suite by typing npm test
. It'll fail, because you have no tests set up, as yet.
Babel
If you're using ES6 modules (i.e. import
statements), which you probably are if you're using Svelte, you'll also ned to install Babel to convert into code that's compatible with Jest.
npm install --save-dev babel @babel/preset-env
Create a Babel config file. I prefer to create a Javascript file babel.config.js
at the root of the project. NB I tried to use an .mjs
file, which would theoretically allow ES6 exports, but this appeared incompatible with usage within Jest.
module.exports = {
presets: [
[
'@babel/preset-env',
{ targets: { node: 'current' } },
],
],
};
Setting up test libraries
We're nearly ready! The last step is to install some test helpers and configure Jest to deal with .svelte
files.
npm install --save-dev babel-jest svelte-jester \
@testing-library/jest-dom @testing-library/svelte
Create a jest.config.mjs
file (this time the ES6 format works!) and add the following configuration:
export default {
transform: {
'^.+\\.js$': 'babel-jest',
'^.+\\.svelte$': 'svelte-jester',
},
moduleFileExtensions: ['js', 'svelte'],
setupFilesAfterEnv: ['<rootDir>/test/jest-setup.js'],
testEnvironment: 'jsdom',
};
Create the file test/jest-setup.js
and add the following content.
import '@testing-library/jest-dom';
This will register the additional assertions from @testing-library/jest-dom
.
- The
transform
config sets upbabel-jest
to deal with.js
files andsvelte-jester
to deal with.svelte
files. - The
moduleFileExtensions
key registers bothjs
andsvelte
files as valid source code for testing. -
setupFilesAfterEnv
loads the setup file we created. - Finally, we set the default Jest test environment to
jsdom
as we'll primarily be working in code targetted at the browser. As stated in the documentation, it's possible to override this for individual test files by adding a@jest-environment
docblock at the top.
Write some tests!
Let's say you have a simple Svelte component called hello.svelte
.
<script>
export let name;
</script>
<h1>Hello { name }!</h1>
Create a test file in the same location called hello.test.js
import { render } from '@testing-library/svelte';
import Hello from './hello';
it('should welcome mum', () => {
const { getByText } = render(Hello, { name: 'mum' });
expect(getByText('Hello mum!')).toBeInTheDocument();
});
This imports the render
function from the @testing-library/svelte
helpers. We use this to instantiate the component, passing in any props as the second argument. In this case, we're setting the name
prop to mum
.
The render function returns a object with a series of helper functions. Here, we're only interested in getByText
, which we destructure from the object.
This searches for elements in the rendered DOM which match the text. In this case, we're looking for an element with the string Hello mum!
. We wrap this in a Jest expect call, using the toBeInDocument
matcher that we registered from jest-dom
to check if the text appears.
Write some more tests!
That's pretty much it. You now need to make sure you're covering all the critical bits of code that you care about! That's beyond the scope of this post, but here are a couple of links to get you started.
As a final thought, one of the tricks that Jest has up it's sleeve is built-in test coverage reporting. Run npm test -- --coverage
to get a report on how much of your code is covered.
You'll notice that you only get coverage stats for code that you're importing into your tests, which means that you could develop a blind spot for modules which you've not yet started.
To fix this, add the following line to the jest.config.mjs
file.
collectCoverageFrom: ['<rootDir>/src/**'],
You'll now see other .svelte
and .js
files listed. Get to work on writing spec for your code! For more details on which code is currently tested, you can open the lcov report that is created for you in coverage/lcov-report/index.html
.
NB I found that coverage reporting sometimes failed unless I added the following line into the Jest configuration. If you have problems, give that a try.
testMatch: ['<rootDir>/src/**/*.test.js'],
Thanks
I hope you've found this article useful. Let me know if you have any other hints for testing Svelte code in the comments below.
Top comments (0)