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

How to enable Istanbul code coverage for the mocha plugin? #1363

Open
factoidforrest opened this issue May 24, 2018 · 48 comments
Open

How to enable Istanbul code coverage for the mocha plugin? #1363

factoidforrest opened this issue May 24, 2018 · 48 comments

Comments

@factoidforrest
Copy link

What problem does this feature solve?

Coverage reporting for unit tests

What does the proposed API look like?

Is there a way to enable coverage for the mocha plugin? When set up manually on another project, you add the istanbul coverage instrumenter as a webpack loader like this:

webpackConfig.module.rules.unshift({
  test: /\.(js)$/,
  loader:  `istanbul-instrumenter-loader`,
  options: {esModules:true},
  exclude: [
    path.resolve(`node_modules`),
    // Exclude tests from test coverage
    path.resolve(`src/tests`),
    /\.(spec|e2e|tests)\.ts$/,
  ]
})

And then you need to add lcov as a reporter.

This explanation is pretty comprehensive:
https://github.com/zinserjan/mocha-webpack/blob/master/docs/guides/code-coverage.md

@oimou
Copy link

oimou commented Jun 14, 2018

I don't know it is an expected answer, but it worked for me by following that mocha-webpack guide and adding the loader to vue.config.js.

You can check whether the rule is successfully added with vue inspect --mode test module.rules:

...
  {
    test: /\.(js|ts)$/,
    include: '/Users/yahatakeiji/work/d3ledger/back-office/src',
    loader: 'istanbul-instrumenter-loader',
    query: {
      esModules: true
    }
  }
...

Also, I changed test:unit script to use nyc as below:

-    "test:unit": "vue-cli-service test:unit",
+    "test:unit": "nyc --reporter=lcov --reporter=text vue-cli-service test:unit",

@factoidforrest
Copy link
Author

Me too! I feel that coverage should be part of vue-cli. I can look at how challenging this would be to add in a PR

@caugner
Copy link
Contributor

caugner commented Jul 16, 2018

Here's how I made test coverage work for both apollo-server and src directory:

UPDATE: This comment is outdated, please check out @stephsavoie's solution below.

[1/4] Install babel-plugin-istanbul + configure it in babel.config.js

yarn add --dev babel-plugin-instanbul
# or
npm install --save-dev babel-plugin-istanbul
// babel.config.js
module.exports = {
  presets: ["@vue/app"],
  plugins: ["istanbul"]
};

[2/4] Install istanbul-instrumenter-loader + configure it in vue.config.js

yarn add --dev istanbul-instrumenter-loader
# or
npm install --save-dev istanbul-instrumenter-loader
// vue.config.js
// ...
  chainWebpack: config => {
    if (process.env.NODE_ENV !== "production") {
      config.module
        .rule("istanbul")
        .test(/\.(js|vue)$/)
        .enforce("post")
        .include.add("apollo-server")
        .add("src")
        .end()
        .use("istanbul-instrumenter-loader")
        .loader("istanbul-instrumenter-loader")
        .options({ esModules: true })
        .end();
    }
// ...

[3/4]: Install nyc + configure it in package.json

yarn add --dev nyc
# or
npm install --save-dev nyc
// package.json
// ...
  "nyc": {
    "check-coverage": true,
    "per-file": true,
    "lines": 90,
    "statements": 90,
    "functions": 90,
    "branches": 90,
    "include": [
      "apollo-server/**/*.js",
      "src/**/*.{js,vue}"
    ],
    "exclude": [
      "apollo-server/*.js",
      "src/*.js",
    ],
    "reporter": [
      "lcov",
      "text",
      "text-summary"
    ],
    "extension": [
      ".js"
    ],
    "cache": true,
    "all": true
  }

[4/4]: Use it

  • Single-run: nyc vue-cli-service test:unit
  • Watched run: nodemon --exec nyc vue-cli-service test:unit

PS: I also recommend adding coverage and .nyc_output to your .gitignore.

@yusufkaracin
Copy link

@caugner

Hi,

I followed your steps but something gone wrong. I'm getting Unable to lookup source: error. src/components showed twice in paths so i couldn't preview coverage report.

screenshot from 2018-08-01 22-07-55

What is your istanbul-instrumenter-loader version and babel-plugin-istanbul version?

Also, my package.json

{
  "name": "tempus",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "test:unit": "nyc vue-cli-service test:unit",
    "test:e2e": "vue-cli-service test:e2e"
  },
  "dependencies": {
    "bulma": "^0.7.1",
    "bulma-timeline": "^3.0.0",
    "register-service-worker": "^1.0.0",
    "vue": "^2.5.16",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.0.0-rc.9",
    "@vue/cli-plugin-e2e-nightwatch": "^3.0.0-rc.9",
    "@vue/cli-plugin-eslint": "^3.0.0-rc.9",
    "@vue/cli-plugin-pwa": "^3.0.0-rc.9",
    "@vue/cli-plugin-unit-mocha": "^3.0.0-rc.9",
    "@vue/cli-service": "^3.0.0-rc.9",
    "@vue/eslint-config-airbnb": "^3.0.0-rc.9",
    "@vue/test-utils": "^1.0.0-beta.20",
    "babel-plugin-istanbul": "^4.1.6",
    "chai": "^4.1.2",
    "istanbul-instrumenter-loader": "^3.0.1",
    "node-sass": "^4.9.0",
    "nyc": "^12.0.2",
    "sass-loader": "^7.0.1",
    "vue-template-compiler": "^2.5.16"
  },
  "nyc": {
    "check-coverage": true,
    "per-file": true,
    "lines": 90,
    "statements": 90,
    "functions": 90,
    "branches": 90,
    "include": [
      "src/**/*.{js,vue}"
    ],
    "exclude": [
      "src/*.js"
    ],
    "reporter": [
      "lcov",
      "text-summary"
    ],
    "extension": [
      ".js"
    ],
    "cache": true,
    "all": true
  }
}

And my vue.config.js

module.exports = {
  chainWebpack: (config) => {
    if (process.env.NODE_ENV !== 'production') {
      config.module
        .rule('istanbul')
        .test(/\.(js|vue)$/)
        .enforce('post')
        .include.add('src')
        .end()
        .use('istanbul-instrumenter-loader')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .end();
    }
  },
};

@janbalaz
Copy link

@caugner thanks, your solution works for me if I use this as babel.config.js:

module.exports = {
  presets: [
    '@vue/app'
  ],
  plugins: [
    'babel-plugin-istanbul'
  ]
}

@Gabsha
Copy link

Gabsha commented Aug 14, 2018

Thanks @caugner , That solution worked for me as well.
I ran across the same issue as @yusufkaracin and setting config.devtool('eval') in my vue.config.js , just above config.module seems to have fixed the source-mapping for vue components.

I got that from this issue.

@phmngocnghia
Copy link

phmngocnghia commented Aug 28, 2018

@caugner can you make example repository on github ? i can't make it work. Very frustrated. I can't find where vue.config.js locate in. Should have use Jest for testing instead of waste time configure this.

@akrawchyk
Copy link
Contributor

I know that coverage is included in Jest by default, should we generate the coverage configuration described above when creating a new Vue app with the Mocha+Chai test options?

@lionel-bijaoui
Copy link

I have updated to vue-cli 3.0.4 and nothing is working.
@caugner Do you still have a working setup ?

@janholas
Copy link

janholas commented Oct 4, 2018

Does anyone have a working example project for test coverage for vue-cli 3.0.x with vue-cli-mocha-plugin? There are very little examples and the snippets we found do not work.

@leoyli
Copy link

leoyli commented Oct 13, 2018

In later version of webpack (shipped in vue-cli) the include.add('src') will resulted in errors, here is my work around:

    const path = require('path')

    if (process.env.NODE_ENV !== 'production') {
      config.devtool('eval')
      config.module
        .rule('istanbul')
          .test(/\.(js|vue)$/)
          .enforce('post')
          .include
            .add(path.resolve(__dirname, '/src'))
            .end()
          .use('istanbul-instrumenter-loader')
            .loader('istanbul-instrumenter-loader')
            .options({ esModules: true })
    }

@jdoubleu
Copy link

jdoubleu commented Nov 21, 2018

I had similar problems and neither @oimou nor @caugner solutions worked.

I finally could track down the mistake:
I put my tests next to my sources, rather than having all tests inside another folder.
When I added the istanbul-instrumenter-loader to my webpack config via vue.config.js I only tested for /\.js$/ which also would include my test files.
Because my test also includes (require) the subject component, obviously, it would be loaded twice. I found this line which causes the

Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
  TypeError: Cannot read property 'fileCoverage' of undefined

error messages.

@martinnaughton
Copy link
Contributor

martinnaughton commented Dec 5, 2018

I can not get this working and I have the same issue as @jdoubleu when i created a project using vue-cli@3.2 . It produces a coverage folder but there is no line coverage in the report. just the same as the out put of the cli below.

I have the same nyc config in my package.json as @yusufkaracin

My vue.config.js file

const path = require('path')

module.exports = { 
  chainWebpack: (config) => {
      var test = path.resolve(__dirname, 'test');
      var src = path.resolve(__dirname, 'src');
      var nodes = path.resolve(__dirname, 'node_modules');
      config.module
        .rule('istanbul')
          .test(/\.(js)$/)
          .enforce('post')
          .include.add(test).add(src)
          .end()
          .exclude.add(nodes)
          .end()
          .use('istanbul-instrumenter-loader')
            .loader('istanbul-instrumenter-loader')
            .options({ produceSourceMap: true, esModules: true }); 
  }
}

one error printed
 WEBPACK  Failed to compile with 1 error(s)

Error in ./src/components/HelloWorld.vue?vue&type=script&lang=js&

  Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
  TypeError: Cannot read property 'fileCoverage' of undefined

 ERROR  mocha-webpack exited with code 1.

=============================== Coverage summary ==================
Statements   : Unknown% ( 0/0 )
Branches     : Unknown% ( 0/0 )
Functions    : Unknown% ( 0/0 )
Lines        : Unknown% ( 0/0 )
================================================================

@jdoubleu
Copy link

jdoubleu commented Dec 12, 2018

I could finally fix the issue for me and it slightly differs from @caugner solution.

Disclaimer: My environment might differ from yours:

Steps to reproduce

Assuming you have already install the mocha plugin.

1.

Install the istanbul-instrumenter-loader webpack plugin since we are using the webpack build system.
I think there is no need to install the babel-plugin-istanbul because we are already using the webpack plugin. However they might also work together somehow.

2.

Add the istanbul-instrumenter-loader to your webpack config using vue-cli's chainWebpack option:

module.exports = {
  ...
  chainWebpack: config => {
    ...

    if (isTesting) {
      config.module.rule('js')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .before('babel-loader')

      config.output
        .devtoolModuleFilenameTemplate('[absolute-resource-path]')
        .devtoolFallbackModuleFilenameTemplate('[absolute-resource-path]?[hash]')

      config.devtool('inline-cheap-module-source-map')
    }
  }
}

Important: Insert the istanbul-instrumenter-loader before the babel-loader! This caused the

TypeError: Cannot read property 'fileCoverage' of undefined

error messages. I guess it had something todo with babel's transformation and he probable reuse of modules inside webpack (as describe in my earlier comment).
I'm not 100% sure if this breaks code coverage for modules written in ES6+ which are transpiled by babel after the istanbul-instrumenter-loader. So far all my modules looked okay.

3.

Update your test command to include all files (even vue). This is required so the instrument loader will also take non tested files into account. Also wrap the test command with nyc
In my case I changed the following scripts in my package.json:

    "test:unit": "vue-cli-service test:unit 'src/renderer/**/*.spec.js'",
    "coverage:unit": "nyc vue-cli-service test:unit 'src/renderer/**/*.{js,vue}'"

4.

(optional) Add a nycrc file:

 {
    "instrument": false,
    "sourceMap": false,
    "reporter": [
        "lcov",
        "text",
        "text-summary"
    ],
    "exclude": [
      "src/renderer/**/*.spec.js",
      "src/renderer/__mocks__/"
    ]
}

At the end this worked for me and the coverage of normal modules seems to be accurate. However I couldn't get coverage reports of .vue files to work (there's an issue).
And I don't know if placing the istanbul-instrumenter-loader before the babel-loader has any drawbacks.

Update: Using before caused the coverage to fail because of exceeded memory usage (FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory).
A quick test showed, that only the post() webpack-chain shorthand does not work.

The istanbul-instrument-loader is included after the babel-loader now, I guess.

My configuration changed to that (vue.config.js):

...
config.module.rule('js')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
...

@node-rookie
Copy link

I can not get this working and I have the same issue as @jdoubleu when i created a project using vue-cli@3.2 . It produces a coverage folder but there is no line coverage in the report. just the same as the out put of the cli below.

I have the same nyc config in my package.json as @yusufkaracin

My vue.config.js file

const path = require('path')

module.exports = { 
  chainWebpack: (config) => {
      var test = path.resolve(__dirname, 'test');
      var src = path.resolve(__dirname, 'src');
      var nodes = path.resolve(__dirname, 'node_modules');
      config.module
        .rule('istanbul')
          .test(/\.(js)$/)
          .enforce('post')
          .include.add(test).add(src)
          .end()
          .exclude.add(nodes)
          .end()
          .use('istanbul-instrumenter-loader')
            .loader('istanbul-instrumenter-loader')
            .options({ produceSourceMap: true, esModules: true }); 
  }
}
one error printed
 WEBPACK  Failed to compile with 1 error(s)

Error in ./src/components/HelloWorld.vue?vue&type=script&lang=js&

  Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
  TypeError: Cannot read property 'fileCoverage' of undefined

 ERROR  mocha-webpack exited with code 1.

=============================== Coverage summary ==================
Statements   : Unknown% ( 0/0 )
Branches     : Unknown% ( 0/0 )
Functions    : Unknown% ( 0/0 )
Lines        : Unknown% ( 0/0 )
================================================================

@martinnaughton I had similar problems, did you solve this problem?

@jpenna
Copy link

jpenna commented May 29, 2019

I am also getting this error. Couldn't find out any solution...

Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
TypeError: Cannot read property 'fileCoverage' of undefined

@silva96
Copy link

silva96 commented May 31, 2019

I can not get this working and I have the same issue as @jdoubleu when i created a project using vue-cli@3.2 . It produces a coverage folder but there is no line coverage in the report. just the same as the out put of the cli below.
I have the same nyc config in my package.json as @yusufkaracin
My vue.config.js file

const path = require('path')

module.exports = { 
  chainWebpack: (config) => {
      var test = path.resolve(__dirname, 'test');
      var src = path.resolve(__dirname, 'src');
      var nodes = path.resolve(__dirname, 'node_modules');
      config.module
        .rule('istanbul')
          .test(/\.(js)$/)
          .enforce('post')
          .include.add(test).add(src)
          .end()
          .exclude.add(nodes)
          .end()
          .use('istanbul-instrumenter-loader')
            .loader('istanbul-instrumenter-loader')
            .options({ produceSourceMap: true, esModules: true }); 
  }
}
one error printed
 WEBPACK  Failed to compile with 1 error(s)

Error in ./src/components/HelloWorld.vue?vue&type=script&lang=js&

  Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
  TypeError: Cannot read property 'fileCoverage' of undefined

 ERROR  mocha-webpack exited with code 1.

=============================== Coverage summary ==================
Statements   : Unknown% ( 0/0 )
Branches     : Unknown% ( 0/0 )
Functions    : Unknown% ( 0/0 )
Lines        : Unknown% ( 0/0 )
================================================================

@martinnaughton I had similar problems, did you solve this problem?

Im also having this problem, I'm also using Typescript and followed this tutorial for typescript
https://istanbul.js.org/docs/tutorials/typescript/

@rndmerle
Copy link

rndmerle commented Jun 19, 2019

This config is working for me, sort of :

devtool: 'eval-source-map'
// ...
config.module
        .rule('js')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .before('babel-loader')
// and the same for rule('ts')

And I removed babel-plugin-istanbul

For .vue files, the fixWebpackSourcePaths options of karma-coverage-istanbul-reporter looks promising (it cleans the resource path from vue-loader which contains the loaders string and query parameters)

@silva96
Copy link

silva96 commented Jun 23, 2019

can anyone help me I'm using

@vue/cli-plugin-unit-mocha and Typescript,

added this in my vue.config.js

const path = require('path')
      config.module
        .rule('istanbul')
        .test(/\.(ts|vue)$/)
        .enforce('post')
        .include.add(path.resolve(__dirname, '/src'))
        .end()
        .use('istanbul-instrumenter-loader')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })

here my nyc config

"nyc": {
    "check-coverage": true,
    "per-file": true,
    "lines": 90,
    "statements": 90,
    "functions": 90,
    "branches": 90,
    "include": [
      "src/**/*.{ts,vue}"
    ],
    "reporter": [
      "lcov",
      "text-summary"
    ],
    "extension": [
      ".ts", "*.vue"
    ],
    "cache": true,
    "all": true
  }

all tests passing, but no coverage generated.

 337 passing (18s)
  3 pending

 MOCHA  Tests completed successfully


=============================== Coverage summary ===============================
Statements   : Unknown% ( 0/0 )
Branches     : Unknown% ( 0/0 )
Functions    : Unknown% ( 0/0 )
Lines        : Unknown% ( 0/0 )
================================================================================

@rndmerle
Copy link

rndmerle commented Jun 23, 2019

@silva96 There are maybe other issues but I'm pretty sure you need to remove the slash from '/src'. And maybe remove the * from "*.vue" too.

@silva96
Copy link

silva96 commented Jun 24, 2019

thanks @rndmerle I fixed that and then the error decribed by others appeared.

Module build failed (from ./node_modules/istanbul-instrumenter-loader/dist/cjs.js):
  TypeError: Cannot read property 'fileCoverage' of undefined

@rndmerle
Copy link

rndmerle commented Jun 24, 2019

Using a dedicated post-rule never worked for me either. What did work was to plug istanbul before babel-loader/ts-loader and cache-loader:

config.module
        .rule('js')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .after('cache-loader')
config.module
        .rule('ts')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .after('cache-loader')

Make sure to check the resulting rules with vue inspect.

@silva96
Copy link

silva96 commented Jun 24, 2019

Using a dedicated post-rule never worked for me either. What did work was to plug istanbul before babel-loader/ts-loader and cache-loader:

config.module
        .rule('js')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .after('cache-loader')
config.module
        .rule('ts')
        .use('istanbul')
        .loader('istanbul-instrumenter-loader')
        .options({ esModules: true })
        .after('cache-loader')

Make sure to check the resulting rules with vue inspect.

@rndmerle that didn't make the trick I believe, can you provide your config nyc in package.json, babel config and vue.config.js ?

@rndmerle
Copy link

rndmerle commented Jun 25, 2019

Here are the config files. However, I'm not using Mocha at all. I came across this thread while trying to configure the coverage on Cypress tests.

.nyrc.json

{
  "include": [
    "src/**/*.{ts,js,vue}"
  ],
  "exclude": [
    "**/*.{spec,test}.{js,ts}",
    "**/*.d.ts",
    "*/types/**/*.ts"
  ],
  "extension": [
    ".ts",
    ".js",
    ".vue"
  ],
  "all": true,
  "check-coverage": false
}

babel.config.js

module.exports = {
  plugins: process.env.COVERAGE === 'true' ? ['istanbul'] : [],
  presets: ['@vue/app'],
}

There is nothing relevant anymore in vue.config.js because I switched from istanbul-instrumenter-loader to babel-plugin-istanbul. Both were working tho.

@silva96
Copy link

silva96 commented Jun 26, 2019

@rndmerle unfortunately it didn't work switching from istanbul-instrumenter-loader to babel-plugin-istanbul

it gives me this error now.

 MOCHA  Testing...

 RUNTIME EXCEPTION  Exception occurred while loading your tests

TypeError: Cannot read property 'f' of undefined
    at Module.getTimezones (/Users/benja/dev/ventanilla-front/dist/webpack:/src/utils/functions.ts:62:1)
    at Module../src/store/modules/settings/getters.ts (/Users/benja/dev/ventanilla-front/dist/webpack:/src/store/modules/settings/getters.ts:35:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/store/modules/settings/index.ts (/Users/benja/dev/ventanilla-front/dist/main.js:408493:66)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/store/index.ts (/Users/benja/dev/ventanilla-front/dist/main.js:372220:75)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/utils/functions.ts (/Users/benja/dev/ventanilla-front/dist/main.js:418113:64)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/types/SeatSelectInput.vue?vue&type=script&lang=ts& (/Users/benja/dev/ventanilla-front/dist/main.js:32054:74)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/components/inputs/types/SeatSelectInput.vue?vue&type=script&lang=ts& (/Users/benja/dev/ventanilla-front/dist/webpack:/src/components/inputs/types/SeatSelectInput.vue?1a11:1:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/components/inputs/types/SeatSelectInput.vue (/Users/benja/dev/ventanilla-front/dist/webpack:/src/components/inputs/types/SeatSelectInput.vue?c837:1:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/ts-loader/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/types/SeatMapBuilder.vue?vue&type=script&lang=ts& (/Users/benja/dev/ventanilla-front/dist/main.js:30215:102)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/components/inputs/types/SeatMapBuilder.vue?vue&type=script&lang=ts& (/Users/benja/dev/ventanilla-front/dist/webpack:/src/components/inputs/types/SeatMapBuilder.vue?a97d:1:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../src/components/inputs/types/SeatMapBuilder.vue (/Users/benja/dev/ventanilla-front/dist/webpack:/src/components/inputs/types/SeatMapBuilder.vue?56f0:1:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at Module../tests/unit/components/inputs/types/SeatMapBuilder.spec.ts (/Users/benja/dev/ventanilla-front/dist/main.js:424121:101)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at run (/Users/benja/dev/ventanilla-front/dist/webpack:/node_modules/mocha-webpack/lib/entry.js:3:1)
    at Array.forEach (<anonymous>)
    at Object../node_modules/mocha-webpack/lib/entry.js (/Users/benja/dev/ventanilla-front/dist/webpack:/node_modules/mocha-webpack/lib/entry.js:10:1)
    at __webpack_require__ (/Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:25:1)
    at /Users/benja/dev/ventanilla-front/dist/webpack:/webpack/bootstrap:116:1
    at Object.<anonymous> (/Users/benja/dev/ventanilla-front/dist/main.js:120:10)
    at Module._compile (internal/modules/cjs/loader.js:723:30)
    at Module.replacementCompile (/Users/benja/dev/ventanilla-front/node_modules/append-transform/index.js:58:13)
    at _module2.default._extensions.(anonymous function) (/Users/benja/dev/ventanilla-front/node_modules/mocha-webpack/lib/util/registerRequireHook.js:148:12)
    at Object.<anonymous> (/Users/benja/dev/ventanilla-front/node_modules/append-transform/index.js:62:4)
    at Module.load (internal/modules/cjs/loader.js:620:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:560:12)
    at Function.Module._load (internal/modules/cjs/loader.js:552:3)
    at Module.require (internal/modules/cjs/loader.js:659:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at /Users/benja/dev/ventanilla-front/node_modules/mocha/lib/mocha.js:250:27
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/Users/benja/dev/ventanilla-front/node_modules/mocha/lib/mocha.js:247:14)
    at Mocha.run (/Users/benja/dev/ventanilla-front/node_modules/mocha/lib/mocha.js:576:10)
    at /Users/benja/dev/ventanilla-front/node_modules/mocha-webpack/lib/runner/TestRunner.js:191:27
    at /Users/benja/dev/ventanilla-front/node_modules/mocha-webpack/lib/webpack/compiler/registerReadyCallback.js:26:7
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/benja/dev/ventanilla-front/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:63:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/benja/dev/ventanilla-front/node_modules/tapable/lib/Hook.js:154:20)
    at emitRecords.err (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:267:22)
    at Compiler.emitRecords (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:449:39)
    at emitAssets.err (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:261:10)
    at hooks.afterEmit.callAsync.err (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:435:14)
    at _err0 (eval at create (/Users/benja/dev/ventanilla-front/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:16:1)
    at callback (/Users/benja/dev/ventanilla-front/node_modules/copy-webpack-plugin/dist/index.js:126:17)
    at afterEmit (/Users/benja/dev/ventanilla-front/node_modules/copy-webpack-plugin/dist/index.js:220:13)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/benja/dev/ventanilla-front/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:12:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/benja/dev/ventanilla-front/node_modules/tapable/lib/Hook.js:154:20)
    at asyncLib.forEachLimit.err (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:432:27)
    at /Users/benja/dev/ventanilla-front/node_modules/neo-async/async.js:2818:7
    at done (/Users/benja/dev/ventanilla-front/node_modules/neo-async/async.js:3522:9)
    at MemoryFileSystem.writeFile (/Users/benja/dev/ventanilla-front/node_modules/memory-fs/lib/MemoryFileSystem.js:328:9)
    at writeOut (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:415:30)
    at asyncLib.forEachLimit (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:426:7)
    at objectIteratorWithKey (/Users/benja/dev/ventanilla-front/node_modules/neo-async/async.js:3509:9)
    at timesSync (/Users/benja/dev/ventanilla-front/node_modules/neo-async/async.js:2297:7)
    at Object.eachLimit (/Users/benja/dev/ventanilla-front/node_modules/neo-async/async.js:3463:5)
    at emitFiles (/Users/benja/dev/ventanilla-front/node_modules/webpack/lib/Compiler.js:321:13)
    at Immediate._onImmediate (/Users/benja/dev/ventanilla-front/node_modules/memory-fs/lib/MemoryFileSystem.js:288:4)
    at processImmediate (timers.js:632:19)

 ERROR  mocha-webpack exited with code 1.

=============================== Coverage summary ===============================
Statements   : Unknown% ( 0/0 )
Branches     : Unknown% ( 0/0 )
Functions    : Unknown% ( 0/0 )
Lines        : Unknown% ( 0/0 )
================================================================================
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! ventas-frontend@0.1.0 test:unit: `nyc vue-cli-service test:unit --require ./tests/unit/setup.js --timeout 10000`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the ventas-frontend@0.1.0 test:unit script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/benja/.npm/_logs/2019-06-26T15_44_03_366Z-debug.log
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! ventas-frontend@0.1.0 test: `npm run test:unit`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the ventas-frontend@0.1.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/benja/.npm/_logs/2019-06-26T15_44_03_396Z-debug.log

@stephsavoie
Copy link

stephsavoie commented Aug 15, 2019

Based on @caugner 's answer, I made it work in a simpler way (by skipping the step 2 and enhanced a bit the nyc configuration in package.json) I'm using Vue CLI-3 with Mocha-webpack as my tests runner.

Here's my current configuration:

[1/3] Install babel-plugin-istanbul + configure it in babel.config.js

npm install --save-dev babel-plugin-istanbul
// babel.config.js
module.exports = {
  presets: [
    '@vue/app'
  ],
  env: {
    test: {
      plugins: [
        ['istanbul', {
          useInlineSourceMaps: false
        }]
      ]
    }
  }
};

[2/3]: Install nyc + configure it in nyc.config.js

npm install nyc --save-dev
// nyc.config.js
module.exports = {
  'check-coverage': false,
  'per-file': true,
  'skip-full': true,
  all: true,
  include: [
    'src/**/*.{js,vue}'
  ],
  exclude: [
    'src/*.js',
    '**/index.js'
  ],
  reporter: [
    'lcov',
    'text',
    'text-summary'
  ],
  extension: [
    '.js',
    '.vue'
  ]
};

[3/3] Use it

nyc vue-cli-service test:unit --require tests/setup.js

No more errors or anything else. I'm not sure if I am missing something but at first sight, coverage report seems to represent the reality of tests scenarios I've created so far.

EDIT: Updated configuration to fix wrong .vue file paths in the coverage report and enhance it to my personal taste

@anymost
Copy link

anymost commented Sep 5, 2019

@stephsavoie Your solution is worked, Thanks a lot.

@thislooksfun
Copy link

@stephsavoie with that solution my nyc output is only showing one .vue file, not all of them.

@lsapan
Copy link

lsapan commented Dec 27, 2019

None of the solutions on here worked for me (either Vue files were excluded, or the line numbers and highlighting in all files was thrown off in the coverage reports). Basically, setting devtool to eval throws off line numbers, but setting it to cheap-module-eval-source-map results in duplication in Vue file paths, throwing Istanbul off.

There's an (admittedly hacky) way to fix this, and it involves just changing one line in one of Istanbul/nyc's dependencies. From the directory containing your vue.config.js file and node_modules directory, you can run this to change the line:

sed -i '' 's/source: pathutils.relativeTo(start.source, origFile),/source: origFile,/' node_modules/istanbul-lib-source-maps/lib/get-mapping.js

Of course, that's annoying to have to do every time the file gets changed (I'm looking at you, yarn), so you can automate running that script every time you go to run your tests.

Just for the sake of completeness, I wrote up a short gist that details everything you need to do to add tests (with coverage) to a Vue project: https://gist.github.com/lsapan/3bfd0ffc0fb3d4a036fce84f6eea142e

@thamerbelfkihthamer
Copy link

@stephsavoie thank you, your solution worked for me, but I'm wondering about the idea behind using tests/setup.js, what's the purpose of it as you did not post the content of this file?

@daneps
Copy link

daneps commented Jan 21, 2020

@stephsavoie This works great, however once I upgraded from vue cli3 to version 4, it no longer works. Have you had any luck with the newer version of the cli?

@batuhantozun
Copy link

batuhantozun commented Feb 18, 2020

I tried a bunch of things but still nyc report is not loading with vue files. Did anyone succeed with vue-cli-4?

@lsapan
Copy link

lsapan commented Feb 18, 2020

@batuhantozun did you try my guide above? It’s a bit hacky, but it works.

https://gist.github.com/lsapan/3bfd0ffc0fb3d4a036fce84f6eea142e

@sebtiz13
Copy link

sebtiz13 commented Apr 6, 2020

Hello for me juste work with

Script in package.json
nyc vue-cli-service test:unit

.nycrc:

{
    "extension": [
      ".js",
      ".vue"
    ],
    "instrument": false,
    "sourceMap": false
}

vue.config.js:

module.exports = {
  chainWebpack: (config) => {
    if (process.env.NODE_ENV === 'test') {
      config.module.rule('js')
        .test(/\.js$/)
        .use('istanbul-instrumenter-loader')
        .loader('istanbul-instrumenter-loader')
        .options({
          esModules: true,
        });
    }
  },
};

Packages:
@vue/cli: 4.3.0
@vue/test-utils: 1.0.0-beta.32
vue: 2.6.11
istanbul-instrumenter-loader: 3.0.1
nyc: 15.0.1

Edit:
Like sayed @lsapan in gist istanbul duplicate the path for .vue files because in source maps the path of source looks like

{
  "source": ["file.vue"],
  "sourceRoot": ["/src/components/" ]
} 

This path it's computed in /src/components/file.vue
and istanbul build path of file with
path.resolve(path.dirname(origFile), file)
origFile it's the absolute path of vue file and file it's path from source map.

So this produce path like /absolute/path/src/components/src/components/file.vue
The js files doesn't have this problems becauses the source it's absolute path (ex: /absolute/path/src/plugins/file.js).

I don't find the option to custom the source for vue file to obtain the absolute path in source,

The generation of source map seems correct for me. For me the problem is in istanbul.js so I have comment this issue to correct the build path in this case.
istanbuljs/istanbuljs#464 (comment)

@arielj
Copy link

arielj commented Apr 20, 2020

@sebtiz13 config worked for me!

@stripathix
Copy link

Hey, @arielj which version of vue-cli are you using?
Are you sure that in your coverage html report it generates you are seeing vue components not test files.

@arielj
Copy link

arielj commented Apr 20, 2020

@stripathix I see code coverage information for the components (not the test files) but I do have that problem on the duplicated src/components string on the path so I can't see the code coverage details line by line on each component (it looks like the data is inside the json report, though), only the table with statements, branches, functions, lines %.

I have vue 2.6.11 and vue-cli-service 4.2.0 inside packages.json

@divukman
Copy link

Hi all, sorry if it's an obvious question, but I'm new to the Vue.
I have followed some of the examples here and now I am getting the coverage for all .vue components, but .js files just show 100 percent coverage, regardless If test exists or not. I must be missing something obvious?

@Jack-Barry
Copy link

Jack-Barry commented Jul 25, 2020

I've tried a few of the solutions here on a Vue CLI (version 4.4.6, uses TypeScript) project with no luck - either I get 0% coverage across the board or it shows coverage for .js and/or .ts files but not .vue files - maybe that's just me being an idiot and expecting something that's not supposed to be there? Is it going to show the .vue files as .js or something like that?

Have a repro up here of the 0% coverage cropping up: https://github.com/Jack-Barry/vue-with-istanbul

Not really sure where to go from here. Feels like I'm in the right neighborhood but walked into the wrong building or something.

Edit: with some tweaks to the config in the demo repo, I've been able to get closer to the goal but still seeing 0% coverage

HelloWorld.vue
    ✓ renders props.msg when passed


  1 passing (30ms)

 MOCHA  Tests completed successfully

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |       0 |        0 |       0 |       0 |                   
 HelloWorld.vue |       0 |        0 |       0 |       0 |                   
----------------|---------|----------|---------|---------|-------------------

@undergroundwires
Copy link

Is there anyone who could get it working with TypeScript so far 😢?

@binhonglee
Copy link

Another comment here to bump this every other month 😞

@bingnz
Copy link

bingnz commented Jan 11, 2021

@undergroundwires:
@rndmerle's comment works for code coverage when using typescript. I got it working with Vue 2.6 as follows:

install packages

npm install nyc istanbul-instrumenter-loader cross-env --save-dev

vue.config.js

// ... other options
,
chainWebpack: config => {
  if (process.env.coverage === "true") {
    config.module
      .rule("ts")
      .use("istanbul")
      .loader("istanbul-instrumenter-loader")
      .options({ esModules: true })
      .before("ts-loader");
  }
}

nyc.config.js

module.exports = {
  all: true,
  instrument: false,
  sourceMap: false,
  include: ["src/**/*.{ts,vue}"],
  reporter: ["lcov", "text", "text-summary"],
  extension: [".ts", ".vue"]
};

package.json

"scripts": {
  "test:unit": "cross-env coverage=true nyc vue-cli-service test:unit",
},

@undergroundwires
Copy link

Hi @bingnz , thanks for your time and effort into compiling such a nice solution 👏🏿 It works cleanly and reports in a pretty way.

However the problem I find with this and other solutions is that they do not report untested classes. So the coverage result is always so high which in fact is not so useful. So all: true in nyc.config.js is not working 😢

@IsaacCespedes
Copy link

IsaacCespedes commented Jan 31, 2021

Bump for a way to view coverage on Mocha test suite. Going to try Wallaby for now.
EDIT: Even Wallaby runs coverage via Jest. This may as well be the only option for testing if you want coverage reports.
EDIT 2: I may have spoken too soon. The auto config is for Jest. Will report my findings on Manual configs.
EDIT 3: It works well. Support is good too. Even better than a test frameworks as it offers IDE-integrated hot reloading. Easily worth the subscription.

@ticlaudeberube
Copy link

I am having an issue with sinon.js ounce I added the configuration for Istanbul the following started to happen and some tests are failing.

Warning in .node_modules/sinon/pkg/sinon-esm.js
critical dependency: require function is used in a way which dependencies cannot be statically extracted.

@vinayakkulkarni
Copy link

Any examples of usage with nuxt ?

@mchl18
Copy link

mchl18 commented May 4, 2021

However the problem I find with this and other solutions is that they do not report untested classes.

Facing the same issue.

@1beb
Copy link

1beb commented Nov 14, 2021

Is there an alternative unit test framework that has coverage built-in that is known to work with Vue? I've tried every iteration of this setup and can't get it to read anything other than js files.

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

No branches or pull requests