Testing with Svelte and Ava

3 minute read

I’m a huge fan of Svelte. It’s design is brilliant, and I thoroughly enjoy building user interfaces with it. However, one aspect that can at times be painful is testing.

With the plethora of test runners and assertion libraries in JavaScript, it’s no surprise. It’s a difficult task to ensure support for any of them without plugins and extensions galore.

Recently, I’ve been using Ava for testing. I find it’s API powerful and it’s configuration simple. It does not try to do too much like some other libraries, and lets you pick and choose the tools that are right for you.

In saying that, there is not support for Svelte out of the box. Today we are going to walk through an example of how to configure Ava to be able to perform unit tests against Svelte components.

Setup

Assuming you have a Svelte application already, let’s install our dependencies.

1npm install --save-dev ava browser-env require-extension-hooks require-extensions-hooks-babel@beta raf

or, if you use yarn

1yarn add -D ava browser-env require-extension-hooks require-extensions-hooks-babel@beta raf

Let’s take a look at these:

Now, let’s create a setup file for ava configuration. Basically this file will be perform some setup for all future tests. Let’s create it at test/_setup.js with the following contents.

Ava setup file
 1// Setup browser environment
 2require('raf').polyfill()
 3require('browser-env')();
 4const hooks = require('require-extension-hooks');
 5const svelte = require('svelte/compiler');
 6
 7// Setup vue files to be processed by `require-extension-hooks-vue`
 8hooks('svelte').push(({content, filename}) => {
 9  const result = svelte.compile(content, {
10    filename,
11    dev: true,
12    css: false,
13  });
14  return {
15    filename,
16    content: result.js.code,
17    sourceMap: result.js.map,
18  };
19});
20// Setup vue and js files to be processed by `require-extension-hooks-babel`
21hooks(['svelte', 'js']).exclude(({filename}) => filename.match(/\/node_modules\//)).plugin('babel').push();

There is a little bit going on in this file. Firstly, we setup the requestAnimationFrame polyfill, then add browser-env for the global js-dom objects. Then, we are adding a hook for the svelte extension. This hook will compile the file being loaded on the fly and return the resulting js. Lastly, we setup babel to run on the svelte and js extensions. Note, you could remove the js extension if it is not required in your configuration.

Now, in our package.json file, we can add the following.

package.json
1"ava": {
2  "require": [
3    "./test/_setup.js"
4  ]
5}

This tells ava to require this file before tests are run.

Writing Tests

Now that our configuration is done, we can start writing tests. As the purpose of this post is not to go into lengthy detail of the ava libraries assertion capabilities, we are going to supply just a simple example of how unit testing with Svelte and Ava works.

App.svelte
 1<script>
 2	export let name;
 3</script>
 4
 5<style>
 6	h1 {
 7		color: purple;
 8	}
 9</style>
10
11<h1>Hello {name}!</h1>

Given the component above, we can now import it in our test files as follows.

test/App.spec.js
 1import test from 'ava';
 2import App from '../src/App.svelte';
 3
 4test('validate name updates', t => {
 5  const target = document.createElement('div');
 6  const app = new App({
 7    target,
 8    props: {
 9      name: 'Jim'
10    },
11  });
12
13  const h1 = target.getElementsByTagName('h1')[0];
14
15  t.is(h1.textContent, "Hello Jim!");
16});

Perfect! With the power of ava’s simple configuration, and the handy require-extension-hooks library, we are able to load Svelte files in our tests.

If you have a different way of writing Svelte tests, feel free to shoot me an email!

Example Project

I have an example project with the above setup here.