Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Code coverage for vue components with isparta #195

Closed
ajbeach2 opened this issue Apr 3, 2016 · 13 comments
Closed

Code coverage for vue components with isparta #195

ajbeach2 opened this issue Apr 3, 2016 · 13 comments

Comments

@ajbeach2
Copy link

ajbeach2 commented Apr 3, 2016

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?

@ajbeach2 ajbeach2 changed the title Code coverage for vue scrtips with isparta Code coverage for vue components with isparta Apr 3, 2016
@yyx990803
Copy link
Member

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

@sorioinc
Copy link

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']
    ]
}

@mediafreakch
Copy link

@sorioinc Did you solve this?

@sorioinc
Copy link

sorioinc commented Jan 3, 2017

@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.

@mediafreakch
Copy link

@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...

@sorioinc
Copy link

sorioinc commented Jan 3, 2017

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']
		}]
	]
}

@mediafreakch
Copy link

mediafreakch commented Jan 4, 2017

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...

@mediafreakch
Copy link

mediafreakch commented Jan 4, 2017

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?

@sorioinc
Copy link

sorioinc commented Jan 5, 2017

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.

@mediafreakch
Copy link

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.

@sorioinc
Copy link

sorioinc commented Jan 5, 2017

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.

@sorioinc
Copy link

sorioinc commented Jan 5, 2017

Although, this is what I'm also experiencing with babel-plugin-istanbul: vuejs-templates/webpack#402 (review)

Sadly, that's a webpack loader.

@fritx
Copy link

fritx commented Sep 20, 2017

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants