There are seemingly a few incompatibilities with Vue and Istanbul/nyc at the moment, making it a bit difficult to set up proper coverage reporting for Vue files. Thankfully, there's a relatively easy way to fix that!
This will walk you through everything you need to do to add tests and coverage reporting to your vue-cli based project.
-
Install dependencies for testing and coverage reporting
yarn add -D @vue/cli-plugin-unit-mocha @vue/test-utils istanbul-instrumenter-loader nyc
Note: You'll also want to install an assertion library like
expect
orchai
, as well as something likesinon
for mocking / spying. -
Create a
.nycrc
file at the root of your project:{ "extension": [ ".js", ".vue" ], "instrument": false, "sourceMap": false }
-
Create a
tests
directory, and create an.eslintrc.js
file within it:module.exports = { env: { mocha: true, }, }
-
Add a
test
command to yourpackage.json
file:{ "scripts": { ... "test": "nyc --reporter=html --reporter=text-summary vue-cli-service test:unit src/**/*/*.{js,vue} tests/**/*.spec.js" } }
Note: I'd recommend adding the
-A
flag in there as well, but that's unrelated. -
Now for the fun part, let's update our
vue.config.js
file:const { execSync } = require('child_process') module.exports = { ... chainWebpack: (config) => { if (process.env.NODE_ENV === 'test') { execSync("sed -i '' 's/source: pathutils.relativeTo(start.source, origFile),/source: origFile,/' node_modules/istanbul-lib-source-maps/lib/get-mapping.js") config.devtool('cheap-module-eval-source-map') config.module.rule('js') .test(/\.js$/) .use('istanbul-instrumenter-loader') .loader('istanbul-instrumenter-loader') .before('babel-loader') .options({ esModules: true, }) } } }
That's it! You can now run yarn test
or npm run test
to test your code! The configuration above assumes you create *.spec.js
files in your tests directory, but feel free to change it to suit your specific needs.
You may be wondering how or why this works. The config
lines probably look reasonable enough, but what in heck is with that execSync
line? Well, for some reason, istanbul ends up duplicating the path for .vue files, which results in not being able to see coverage for them. There's a bunch of issues about this, but the general consensus is to change devtool
to eval
, which removes the duplication from the path.
The problem with using eval
though, is that the line numbers and highlighting gets thrown off for ALL files. Seems like a lot of folks are just accepting that, but we can actually use a proper devtool if we change the offending line in istanbul's code.
I'm sure they have that line in there for a reason (there are so many uses cases), but our use case doesn't need it. It also means we can't really submit a PR. Instead, we can just change the source code locally automatically, which is what that disgusting line does. When this eventually gets fixed, you can remove it!
@isapan, many thanks for this guide!
Is the sed command meant to have that first blank argument? If I run it with that, it errors and exits. Removing it resolves that, and we then have test coverage.
In case it's relevant: