Vue-loader: Code coverage for vue components with isparta

Created on 3 Apr 2016  路  13Comments  路  Source: vuejs/vue-loader

I am trying to get isparata to work with vue.js, so i can see code coverage of the scripts of my vue.js components.

However, this doesn't seem possible: My loader in my Karma config file looks like the following:

    {
      test: /\.vue$/,
      loader: 'isparta!vue'
    },

which produces a code coverage report that looks like this:

var __vue_script__, __vue_template__
__vue_script__ = require("!!babel!eslint!./../../node_modules/vue-loader/lib/selector.js?type=script&index=0!./Song.vue")
Iif (__vue_script__ &&
    __vue_script__.__esModule &&
    Object.keys(__vue_script__).length > 1) {
  console.warn("[vue-loader] src/components/Song.vue: named exports in *.vue files are ignored.")}
__vue_template__ = require("!!vue-html-loader!./../../node_modules/vue-loader/lib/selector.js?type=template&index=0!./Song.vue")
module.exports = __vue_script__ || {}
Eif (module.exports.__esModule) module.exports = module.exports.default
Eif (__vue_template__) {
(typeof module.exports === "function" ? (module.exports.options || (module.exports.options = {})) : module.exports).template = __vue_template__
}

How can I get the vue-loader to only pass back the source map to isparata?

All 13 comments

You need to apply isparta only to the js part of vue files, so you need to use the vue option inside your webpack config. See the test config in the official webpack template: https://github.com/vuejs-templates/webpack/blob/master/template/test/unit/karma.conf.js#L16

This very same happens to me but with Browserify. I get correct mapping from the rest of the javascript files, except the *.vue, it shows the transpiled code. Any thoughts?

browserify: {
    debug: true,
    plugin: [require('proxyquireify').plugin],
    extensions: ['.vue', '.js'],
    transform: [
        ['vueify'],
        istanbul({
            instrumenterConfig: { embedSource: true },
            instrumenter: isparta,
            ignore: [
                '**/node_modules/**',
                '**/test/**'
            ]
        }),
        ['babelify']
    ]
}

@sorioinc Did you solve this?

@mediafreakch I started looking into this last week. I tried many things and surprisingly I didn't use istanbul or browserify directly; finally got it working by using karma karma-coverage babel-plugin-istanbul, nothing else. This repo set me on the right track: https://github.com/kt3k/example-karma-browserify-babel-istanbul hope it helps.

@sorioinc Are you using this now to assess the coverage of .vue components or just plain .js files? The repo you linked to does not use vueify and .vue components at all...

I was singing victory too fast... however, the last 16 hours, after going through the guts of vueify, babelify, istanbul-lib-instrument and babel-core... Found that adding babelify (with the extension option) to your browserify transforms will do just what I was after:

browserify: {
    debug: true,
    plugin: [require('proxyquireify').plugin],
    transform: [
        'vueify',
        'rewireify',
        './static/js/rewireify-istanbul-ignore',
        ['babelify', {
            extensions: ['.js', '.vue'],
            presets: ['es2015'],
            plugins: ['istanbul']
        }]
    ]
}

Are the rewireify and ./static/js/rewireify-istanbul-ignore part relevant to get code coverage for .vue files working? If so, do you might share the contents of the latter with me? :)

Also, does the report look correct if you look at a .vue file? Because for me it doesn't. What I see in the report doesn't seem to match what has been coverage tested...

I found a karma.conf.js configuration that shows more promising results :

module.exports = function (config) {
  config.set({
    browsers: ['PhantomJS'],
    frameworks: ['browserify', 'jasmine'],
    files: ['spec/*.spec.js'],
    reporters: ['dots', 'coverage'],
    preprocessors: {
      'spec/*.spec.js': [ 'browserify' ]
    },
    browserify: {
      debug: true,
      transform: [
        [ 'vueify', { babel: { presets: [ 'es2015' ], plugins: [ ['istanbul', { exclude: '**/*.spec.js' }]] } }], // this is needed so that istanbul can instrument the javascript code inside .vue files
        [ 'babelify', { presets: [ 'es2015' ], plugins: [ ['istanbul', { exclude: '**/*.spec.js' }] ] }] // this is only needed if you want to write ES6 code in your .spec files
      ]
    },
    singleRun: true
  })
}

Make sure you have babel-plugin-istanbul, babelify, babel-core and any babel presets installed you want to use.

The thing I cannot wrap my head around is that the coverage is not influenced by my unit tests that check whether a component property behaves correctly.

// spinner.vue
<template>
  <transition>
    <svg class="spinner" :class="{ show: show }" v-show="show" width="44px" height="44px" viewBox="0 0 44 44">
      <circle class="path" fill="none" stroke-width="4" stroke-linecap="round" cx="22" cy="22" r="20"></circle>
    </svg>
  </transition>
</template>

<script>
  export default {
    props: ['show'],
    methods: {
      foo() {
        var doit;
        if (doit) {
          console.log('foo');
        }
      }
    }
  }
</script>
// spinner.spec.js
import Spinner from '../src/components/Spinner.vue'
import Vue from 'vue'

// helper function that mounts and returns the rendered text
function render (Component, propsData) {
  const Ctor = Vue.extend(Component)
  const vm = new Ctor({ propsData }).$mount()
  return vm.$el
}

describe('Spinner.vue', () => {
  it('should be hidden by default', () => {
    let el = render(Spinner)
    expect(el.style.display).toBe('none')
  })

  it('should become visible when prop changes to "show"', () => {
    let el = render(Spinner, { show: true })
    expect(el.style.display).not.toBe('none')
  })
})

The coverage report shows that if (doit) { ... } is not covered. Shouldn't it also says that foo() is not covered? And why do my unit tests not affect overall coverage. Is this the expected behaviour?

What version of Vueify are you using 9.x? I'm still using the previous version, my project is Vue 1.x. Being said that, versi贸n 8.x doesn't send the filename to babel-core and 9.x does -
8x: https://github.com/vuejs/vueify/blob/8.x/lib/compilers/babel.js#L8
9.x: https://github.com/vuejs/vueify/blob/master/lib/compilers/babel.js#L45

And yes, the generated report seems kind of off, however the percentages seem fine.

Btw, you can have the babel options in the root directory of you project on a file called .babelrc, you can even configure environments if you use cross-env (although looking at Vueify source code, it doesn't respect the latter).

Please don't mind the rewireify transforms, I did not intend to send them in the snippet.

In Vue 1.x I mount the vm and extract the component, then get to call the component's method explicitly like: component.foo(). What is './support/helpers'?

const getComponent = () => {
    let vm = new Vue({
        template: `<div><custom-component v-ref:component ></custom-component></div>`,
        components: {
            CustomComponent
        }
    });
    return vm.$mount();
};
beforeEach(() => {
    document.body.insertAdjacentHTML('afterbegin', '<app></app>');
});
it('should call method', () => {
    const consoleSpy = sandbox.spy(console, 'log');
    const vm = getComponent();
    const component = vm.$refs.component;
    component.foo();
    expect(consoleSpy).to.have.been.calledWith('foo');
});

I don't see where you call it explicitly or make that piece of code run and assert on it.

Oh ok I'm using Vue 2 with vueify 9.x.

I updated my previous comment to give clarity about the helpers. I'm using a helper function that mounts my component and renders it with the props data I pass to it.

In my example I intentionally don't assert the foo() function because I wanted to see if the coverage report is working. However something still seems to be off but I cannot figure out what it is.

If it's of any help, the Webpack template for Vue dropped isparta for babel-plugin-istanbul in this PR: https://github.com/vuejs-templates/webpack/pull/402/files, just 6 days ago.

Although, this is what I'm also experiencing with babel-plugin-istanbul: https://github.com/vuejs-templates/webpack/pull/402#pullrequestreview-12219235

Sadly, that's a webpack loader.

Btw, is it able to code-coverage branches in vue <template> section?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

snoopdouglas picture snoopdouglas  路  3Comments

lijialiang picture lijialiang  路  3Comments

C0deZLee picture C0deZLee  路  3Comments

flashios09 picture flashios09  路  3Comments

jorgy343 picture jorgy343  路  3Comments