DEV Community

Cover image for Svelte test suite setup
Giles Dring
Giles Dring

Posted on

Svelte test suite setup

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
Enter fullscreen mode Exit fullscreen mode

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"
  }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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' } },
    ],
  ],
};
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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',
};
Enter fullscreen mode Exit fullscreen mode

Create the file test/jest-setup.js and add the following content.

import '@testing-library/jest-dom';
Enter fullscreen mode Exit fullscreen mode

This will register the additional assertions from @testing-library/jest-dom.

  • The transform config sets up babel-jest to deal with .js files and svelte-jester to deal with .svelte files.
  • The moduleFileExtensions key registers both js and svelte 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>
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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/**'],
Enter fullscreen mode Exit fullscreen mode

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'],
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)