javascripttestingvue.jsava

How to test single file Vue components


I would like to use ava for unit testing my Vue components. Right now I have a very simple setup:

package.json

{
    "name": "vue-testing",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "babel": {
        "presets": [
            "es2015"
        ]
    },
    "ava": {
        "require": [
            "babel-register",
            "./test/helpers/setup-browser-env.js"
        ]
    },
    "devDependencies": {
        "ava": "^0.18.1",
        "babel-preset-es2015": "^6.24.1",
        "babel-register": "^6.22.0",
        "browser-env": "^2.0.21"
    },
    "dependencies": {
        "vue": "^2.1.10"
    }
}

./test/helpers/setup-browser-env.js

import browserEnv from 'browser-env';

browserEnv();

./test/Notification.js

import Vue from 'vue/dist/vue.js';
import test from 'ava';
import Notification from '../src/Notification';

let vm;

test.beforeEach(t => {
    let N = Vue.extend(Notification);

    vm = new N({ propsData: {
        message: 'Foobar'
    }}).$mount();
});


test('that it renders a notification', t => {
    t.is(vm.$el.textContent, 'FOOBAR');
});

src/Notification.js

export default {
    template: '<div><h1>{{ notification }}</h1></div>',
    props: ['message'],
    computed: {
        notification() {
            return this.message.toUpperCase();
        }
    }
};

When I run ava everything works as expected: 1 passed.

I'd be more happy if I could use the following component syntax:

./src/Notification.vue

<template>
    <div>
        <h1>{{ notification }}</h1>
    </div>
</template>
<script>
export default {
     props: ['message'],

    computed: {
        notification() {
            return this.message.toUpperCase();
        }
    }
}
</script>

But then ava will return the following error:

> 1 | <template>
    | ^
  2 |     <div>
  3 |         <h1>{{ notification }}</h1>
  4 |     </div>

I can't figure out how to make this work, any help would be greatly appreciated!


Solution

  • Problem

    You need to compile .vue files into JavaScript before running them.

    Solution

    You can run vue-loader on modules as you require them using vue-node.

    Run npm install --save-dev vue-node, to add vue-node to your project

    In your /helpers dir, create a setup.js file

    Add the following:

    const hook = require('vue-node');
    const { join } = require('path');
    
    // Pass an absolute path to your webpack configuration to the hook function.
    hook(join(__dirname, './path/to/webpack.config.js'));
    

    Where ./path/to/webpack.config.js is the path to a webpack config with vue-loader, relative to your project.

    In package.json, add

    "ava": {
      "require": [
        "./test/helpers/setup.js"
      ]
    },
    

    as a property.

    You can see a working example repo here - https://github.com/eddyerburgh/avoriaz-ava-example

    Alternatives

    This thread showcases a few ways of testing with ava.