Testing with Svelte and Ava
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:
- ava - The package for the ava test runner
- browser-env - The package for using js-dom with globals for object such as
document
- require-extension-hooks - Add hooks for js extension types
- require-extension-hooks-babel - A hook for processing extensions with babel
- raf - A global mock for requestAnimationFrame
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.