jest-vue-preprocessor: Code coverage is incorrect

expected 100% , but only got 93.75%

screen shot 2017-04-01 at 12 45 28 pm

P.S.

  • jest: ^19.0.2
  • jest-vue-preprocessor: ^0.2.0,
  • Node: 7.8
// Hello.spec.js
import Vue from 'vue'
import Hello from '@/components/Hello'

describe('Hello.vue', () => {
  it('should render correct contents', () => {
    const Constructor = Vue.extend(Hello)
    const vm = new Constructor().$mount()
    expect(vm.$el.querySelector('.hello h1').textContent)
      .toBe('Welcome to Your Vue.js App')
  })
})
// package.json
"jest": {
    "collectCoverage": true,
    "moduleNameMapper": {
      "src/components/([^\\.]*)$": "<rootDir>/src/components/$1.vue",
      "^vue$": "vue/dist/vue.common.js",
      "src/([^\\.]*)$": "<rootDir>/src/$1.vue",
      "(.*)/(.*)$": "$1/$2.vue"
    },
    "moduleFileExtensions": [
      "js",
      "vue"
    ],
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      ".*\\.(vue)$": "<rootDir>/node_modules/jest-vue-preprocessor"
    }
  },

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 5
  • Comments: 19 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Hi, I’ve spent a lot of time on the wrong coverage values and the spawn of the undefined file on my root folder ; and I’ve finally figured out why.

TL;DR

Remove the plugin istanbul from your .babelrc file.

{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    "stage-2"
  ],
  "plugins": ["transform-runtime"],
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      -> "plugins": ["istanbul"]
    }
  }
}

The cause

When you generate a project from the vue-webpack template, the babel configuration automatically includes the istanbul plugin for the test env. This plugin is mandatory when your want the coverage with mocha and chai. However, Jest comes with istanbul and will add hook functions (needed by istanbul) on the transpiled code produced by Babel. Babel is also configured to add hook functions due to the istanbul plugin. That’s why the coverage computed by jest’s istanbul is not your actual code but your code + the babel’s istanbul code! As the istanbul babel plugin is not needed by jest you can remove it from the .babelrc file.

Hope it will save you, hours of search.

I removed babel from my list of plugins to avoid it over-taking jest’s coverage and I added mapCoverage: true to my jest config. What happened is : the same line appears as “untested” but also now one of my tests doesn’t show up at all in the coverage report. 🤔

~/v/bcgdv-voting (master|●2✚3…) $ yarn list vue jest jest-vue-preprocessor babel-jest
yarn list v1.0.2
├─ babel-jest@21.2.0
├─ jest-vue-preprocessor@1.3.1
├─ jest@21.2.1
└─ vue@2.5.2
✨  Done in 0.90s.
  "jest": {
    "moduleNameMapper": {
      "^vue$": "vue/dist/vue.common.js",
      "@(.*)$": "<rootDir>/src/$1"
    },
    "moduleFileExtensions": [
      "js",
      "vue"
    ],
    "mapCoverage": true,
    "transform": {
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      ".*\\.(vue)$": "<rootDir>/node_modules/jest-vue-preprocessor"
    }
}
~/v/bcgdv-voting (master|●2✚3…) $ yarn test
yarn test v1.0.2
$ jest --coverage
 PASS  src/components/Question/Question.spec.js
 PASS  src/components/QuestionsList/QuestionsList.spec.js

Test Suites: 2 passed, 2 total
Tests:       3 passed, 3 total
Snapshots:   2 passed, 2 total
Time:        1.551s
Ran all test suites.
--------------------------|----------|----------|----------|----------|----------------|
File                      |  % Stmts | % Branch |  % Funcs |  % Lines |Uncovered Lines |
--------------------------|----------|----------|----------|----------|----------------|
All files                 |    36.59 |    33.33 |      6.9 |    36.59 |                |
 api                      |    29.41 |        0 |        0 |    29.41 |                |
  index.js                |    29.41 |        0 |        0 |    29.41 |... 25,30,31,33 |
 components/QuestionsList |      100 |       50 |      100 |      100 |                |
  QuestionsList.vue       |      100 |       50 |      100 |      100 |             19 |
 store                    |    34.43 |      100 |     6.25 |    34.43 |                |
  actions.js              |       25 |      100 |        0 |       25 |... 39,40,41,43 |
  getters.js              |      100 |      100 |      100 |      100 |                |
  index.js                |      100 |      100 |      100 |      100 |                |
  mutation-types.js       |      100 |      100 |      100 |      100 |                |
  mutations.js            |        0 |      100 |        0 |        0 |... 35,36,37,40 |
--------------------------|----------|----------|----------|----------|----------------|
✨  Done in 3.83s.

QuestionList.vue:L19

      <v-btn
          large
          color="primary"
          :block="$vuetify.breakpoint.xsOnly"
          v-if="!maxPagesReached"
          @click="$store.dispatch('requestItems')">
        Load More Questions</v-btn>

and it’s spec:

store.dispatch = jest.fn();
import Vue from 'vue';
import { mount } from 'vue-test-utils';
import QuestionsList from './QuestionsList';
import store from '@/store';

Vue.prototype.$vuetify = {
  load: (fn) => fn(),
  breakpoint: {}
};

describe('QuestionsList.spec.js', () => {
  let cmp;
  let template;
  
  beforeEach(() => {
    cmp = mount(QuestionsList, {
      store,
    });
    template = cmp.html();
  });
  
  it('has the expected html structure', () => {
    expect(template).toMatchSnapshot()
  });
  
  it('should emit 2 dispatch events', () => {
    expect(store.dispatch.mock.calls.length).toBe(2);
  });
  
});

Why is L19 of QuestionsList reported as uncovered and why’s Question.vue disappearing from the report when Is add mapCoverage: true?

To pass source maps to Jest you return an object like this from process:

module.exports = {
  process (src, path) {
    // logic
    return {
      code: output,
      map: sourceMap
    }
  }
}

For the source map to be used by Jest, you need to set mapCoverage to true - https://facebook.github.io/jest/docs/configuration.html#mapcoverage-boolean

You can generate a sourcemap using the source-map module. As you identified, if there are existing source maps you need to combine these with the new source map you generate.

You can see this done in vueify - https://github.com/vuejs/vueify/blob/master/lib/compiler.js#L187

@Xiphe every PR is welcome here, when you have time you can dig into the approach vueify is using

That would be awesome! Let me know when you need any help or rather would like a PR instead of own digging 😃

in the jest.conf.js work fine

//mapCoverage: true, testURL: ‘http://localhost

Disclaimer: typescript sourcemaps are still off when I tested it. Not sure how to fix that I propose someone with more typescript know how looks into that.

I gave this another try. The spike of @johnsardine works quite nice (once mapCoverage is enabled 😬 )

Another problem is that generateOutput is shifting the source mapping so I wrote a babel inline plugin for that.

My current state is really dirty but works for my usecase

https://github.com/sumcumo/jest-vue-preprocessor/tree/support-sourcemaps

Following things need to be done before I open a PR

  • cleanup
  • support ts
  • fix existing tests
  • add tests for new behaviour

@lyyourc I also have this problem. I was able to get it working, kind of, but then the coverage does not match 100%.

I have created a fork https://github.com/johnsardine/jest-vue-preprocessor that provides a source map to the jest transform

I also created an installation with that package https://github.com/johnsardine/vue-jest

Can you try it and give some feedback?

Perhaps the author of this repo already has an idea of how to fix this