pocesar/grunt-mocha-istanbul

Run tests written in ES6

Closed this issue · 23 comments

Hi. I have my code written in ES6 and I successfully test by passing babel-instanbul to the scriptPath option. However I would like to write in ES6 my tests as well. The author of babel-istanbul suggests to do that by running the script with babel-node. Unfortunately I do not see a way to do that using grunt-mocha-istanbul. I was only able to get it to run by manually modifying the value of cmd in tasks/index.js to contain the path to babel-node.

Could you add the support for tests in ES6 to grunt-mocha-istanbul?

+1

You can do this by following

options: {
         ...
         require: 'test/mocha-babel',
        ...
}

and

cat test/mocha-babel.js
require('babel/register')({
  'optional': [
    'es7.classProperties'
  ],
  'blacklist': []
});

@jithin1987 when I was trying that with mochaOptions: ['--require=babel/register'] I got an error message from the coverage generation step. Are you sure that works?

The approach I pasted above works for me.

@jithin1987 thank you, I will try it. I can't see the difference though.

@jithin1987 it doesn't work for me. Here's my configuration:

options: {
    scriptPath: 'node_modules/.bin/babel-istanbul',
    require: 'tests/mocha-babel',
    coverageFolder: 'tests/results/backend_coverage'
},
backendHtml: {
    src: ['tests/backend/common/net/**/*.spec.js']
}

And I get this exception:

node_modules/babel-istanbul/lib/report/html.js:236
        text = structuredText[startLine].text;
                                        ^
TypeError: Cannot read property 'text' of undefined
    at node_modules/babel-istanbul/lib/report/html.js:236:45
    at Array.forEach (native)
    at annotateFunctions (node_modules/babel-istanbul/lib/report/html.js:219:26)
    at HtmlReport.Report.mix.writeDetailPage (node_modules/babel-istanbul/lib/report/html.js:422:9)
    at node_modules/babel-istanbul/lib/report/html.js:484:26
    at SyncFileWriter.extend.writeFile (node_modules/babel-istanbul/lib/util/file-writer.js:57:9)
    at FileWriter.extend.writeFile (node_modules/babel-istanbul/lib/util/file-writer.js:147:23)
    at node_modules/babel-istanbul/lib/report/html.js:483:24
    at Array.forEach (native)
    at HtmlReport.Report.mix.writeFiles (node_modules/babel-istanbul/lib/report/html.js:477:23)
    at node_modules/babel-istanbul/lib/report/html.js:479:22
    at Array.forEach (native)
    at HtmlReport.Report.mix.writeFiles (node_modules/babel-istanbul/lib/report/html.js:477:23)
    at HtmlReport.Report.mix.writeReport (node_modules/babel-istanbul/lib/report/html.js:561:14)
    at LcovReport.Report.mix.writeReport (node_modules/babel-istanbul/lib/report/lcov.js:55:19)
    at node_modules/babel-istanbul/lib/reporter.js:93:20
    at Array.forEach (native)
    at Object.Reporter.write (node_modules/babel-istanbul/lib/reporter.js:87:30)
    at process.<anonymous> (node_modules/babel-istanbul/lib/command/common/run-with-cover.js:267:30)
    at process.g (events.js:199:16)
    at process.emit (events.js:129:20)
    at process.exit (node.js:600:17)
    at done (node_modules/mocha/bin/_mocha:406:32)
    at afterWrite (_stream_writable.js:361:3)
    at _stream_writable.js:349:9
    at process._tickCallback (node.js:355:11)

@arty-name You should check why structuredText[startLine] is undefined. I don't think it has much to do with babel.

Also versions I use are

grunt-mocha-istanbul": "~3.0.1",
mocha": "^2.3.3",
isparta": "^3.5.3",

And I am using isparta instead of istanbul since isparta provides coverage report for original es6/7 code not the transpiled one.

@jithin1987 the last time I saw that error was when I was introducing babel. It was thrown from parts of code dealing with source maps and stuff. I then switched to babel-istanbul and that solved the problem. So I am pretty confident that it has to do with transformations and babel.

For me babel-istanbul also provides coverage of the original code.

@arty-name maybe a nitpick, but your options should be

backendHtml: {
    src: ['tests/backend/common/net/**/*.spec.js'],
    options: {
      scriptPath: require.resolve('babel-istanbul/lib/cli'),
      require: 'tests/mocha-babel',
      coverageFolder: 'tests/results/backend_coverage'
   }
}

@pocesar thank you for the advise. Could you add the support for tests in ES6 to grunt-mocha-istanbul?

@arty-name the tests are actually ran by mocha, and mocha needs to understand that your test code is in ES6, it's not a problem with grunt-mocha-istanbul itself, but rather the way you need to pass the options to mocha.
You'll need to do:

options: {
   mochaOptions: ['--compilers', 'js:babel/register']
}

The only problem is that the errors that might show up can point to the compiled version of the test, and might be harder to spot. If you want to separate js (plain ES5) to ES6, name your files like test.spec.es6 then set the compilers to es6:babel/register

@pocesar for me it not just "tests are run by mocha". For me it's like that: node runs grunt, who runs grunt-mocha-istanbul, who runs babel-istanbul, who runs mocha, who runs tests. If I take grunt and grunt-mocha-istanbul out of the picture, I can replace node with babel-node, and then everything is fine: tests and code can be written in ES6. ES6 in tests is handled by babel-node, while ES6 in code is handled by babel-istanbul. But as soon as I add grunt-mocha-istanbul, I cannot use babel-node, and therefore I cannot use ES6 in tests.

The solution you are proposing does not work either. If I pass babel to mocha, then the coverage information will be messed up, because istanbul cannot run mocha with babel. To have coverage for ES6 code I have to use babel-istanbul. If I want in addition to write tests in ES6 I have to run babel-istanbul with babel-node. But I am running babel-istanbul with grunt-mocha-istanbul, and it does not let me use babel-node.

This is why I am asking you to add support for babel-node to grunt-mocha-istanbul.

I'm not sure if this is related but I get:

No coverage information was collected, exit without writing coverage information
ERROR: No coverage files found.
Warning:  Use --force to continue.

This happens when passing one of the following:

mochaOptions: ['--require=babel-core/register'],
mochaOptions: ['--require=babel-register'],
mochaOptions: ['--compilers=js:babel-core/register'],
mochaOptions: ['--compilers=js:babel-register'],

When I do not use Babel but Node 5 - which supports ES6 natively - a coverage report is generated.

I simply give up on this. The only way I can get a coverage report to be generated is to run the command manually using babel-node instead of node. Any other way (and I have tried a lot - all of the suggestions here and many more) and I get no coverage report generated.

I don't see any examples of anybody having this working.

This the closest I got:

module.exports = {
  server: {
    options: {
      scriptPath: require.resolve('isparta/bin/isparta'),
      // scriptPath: './node_modules/.bin/babel-istanbul',
      mask: '**/*.test.js',
      coverageFolder: 'server/coverage',
      reportFormats: ['text'],
      require: [
        // 'babel-core/register',
        // 'server/test/mocha-babel'
        'babel-polyfill',
        'babel-register'
      ],
    },
    src: 'server/test',
  }
};

Unfortunately, this or any permutation of it that I could think of was enough.

The only thing I can see that works it to hack this module so that it uses babel-node, add an option to support using babel-node, or forget it all.

In the end I went with simply running the command from npm run as

babel-node ./node_modules/.bin/isparta cover --dir=./server/coverage --report=text _mocha -- --report=text server/test/**/*.test.js

And then I use https://github.com/cri5ti/grunt-shell-spawn to run npm run tets:server from within grunt. Not ideal but I'm done missing with this! Thanks anyway.

@mrfelton based on your post, I've made a few additions to the task, see if it works for you https://github.com/pocesar/grunt-mocha-istanbul/tree/issue%2349

Basically you need to set (in your case):

options: {
    nodeExec: 'babel-node',
    scriptPath: require.resolve('isparta/bin/isparta'),
    reporter: 'text',
    reportFormats: ['text']
}

Good stuff @pocesar - that does work, although adding reporter: 'text' as you suggested results in an error

"text" reporter not found

I also needed to set nodeExec to ./node_modules/.bin/babel-node since babel-node is not installed globally (recommended by the babel team).

@mrfelton yes, my bad, 'text' is a istanbul reporter not a mocha reporter ;)
see if you can change that line to nodeExec: require.resolve('babel-cli/bin/babel-node') or nodeExec: require.resolve('.bin/babel-node')

need to know if the code in https://github.com/pocesar/grunt-mocha-istanbul/tree/issue%2349 can be merged into master, can anyone hint me what is working and what isn't

I’d like to help, but I changed the job in the meantime :) Don’t have access to the old code. Hopefully @mrfelton can comment.

@arty-name thanks anyway, I never dealt with untranspiled code before, I mainly use Typescript, then have a build step, so I'm always working with ES5. If you have any idea how I could setup a simple test case using ES2015+, would be great

I can’t really recall all the details. Maybe @fustic will be able to dig it up it the gruntfile history.

@arty-name gruntfile history doesn't give much more details then you have already specified here.
I would say we can close the issue. Seems like no one else facing this issue and we fully migrated to webpack, so we write all code/tests in ES6/7.

should be good to go in version 5.0.0