UNPKG

grunt-mocha-istanbul

Version:

Almost config-free Istanbul code coverage reporter for Mocha usage in Grunt

358 lines (310 loc) 11.8 kB
module.exports = function (grunt) { 'use strict'; var path = require('path'); function getMochaPath() { try { return require.resolve('mocha/bin/_mocha'); } catch (ignored) { grunt.fail.fatal('Mocha peer dependency missing. Please "npm install mocha"'); } } function getIstanbulPath() { try { return require.resolve('istanbul/lib/cli'); } catch (ignored) { grunt.fail.fatal('Istanbul peer dependency missing. Please "npm install istanbul"'); } } function arrayOfStrings(options, name, exec) { if (Array.isArray(options)) { if (options.length) { exec(options); } else { grunt.verbose.ok('Skipping empty ' + name + ' array') } } else { grunt.fail.fatal(name + ' must be an array of strings'); } } function defaultOptions() { return { require: [], ui: false, globals: [], reporter: false, timeout: false, coverage: false, slow: false, includes: false, grep: false, dryRun: false, quiet: false, recursive: false, mask: false, root: false, print: false, noColors: false, harmony: false, coverageFolder: 'coverage', cwd: process.cwd(), reportFormats: ['lcov'], check: { statements: false, lines: false, functions: false, branches: false }, excludes: false, mochaOptions: false, istanbulOptions: false, nodeOptions: false, nodeExec: process.execPath }; } function executeCheck(callback, coverageFolder, options) { var args = [], check = options.check; if ( check.statements !== false || check.lines !== false || check.functions !== false || check.branches !== false ) { args.push(options.scriptPath); args.push('check-coverage'); if (check.lines) { args.push('--lines'); args.push(check.lines); } if (check.statements) { args.push('--statements'); args.push(check.statements); } if (check.functions) { args.push('--functions'); args.push(check.functions); } if (check.branches) { args.push('--branches'); args.push(check.branches); } args.push(coverageFolder + '/coverage*.json'); grunt.verbose.ok('Will execute: ', options.nodeExec + ' ' + args.join(' ')); if (!options.dryRun) { grunt.util.spawn({ cmd: options.nodeExec, args: args, opts: { env: process.env, cwd: options.cwd, stdio: options.quiet ? 'ignore' : 'inherit' } }, function (err) { if (err) { callback && callback(err); return; } callback && callback(null, 'Done. Minimum coverage threshold succeeded.'); }); return; } else { callback && callback(null, 'Would also execute post cover: ' + options.nodeExec + ' ' + args.join(' ')); return; } } callback && callback(); } grunt.registerMultiTask('istanbul_check_coverage', 'Solo task for checking coverage over different or many files.', function () { var done = this.async(); var options = this.options(defaultOptions()); // only execute this function if no scriptPath is specified if (!options.scriptPath) { options.scriptPath = getIstanbulPath(); } executeCheck(function (err, result) { if (err) { return done(err); } if (options.coverage) { var coverage = grunt.file.read(path.join(options.coverageFolder, 'lcov.info')); return grunt.event.emit('coverage', coverage, function (d) { grunt.log.ok(result || 'Done. Check coverage folder.'); done(d); }); } grunt.log.ok(result || 'Done. Check coverage folder.'); done(); }, options.coverageFolder, options); }); grunt.registerMultiTask('mocha_istanbul', 'Generate coverage report with Istanbul from mocha test', function () { if (!this.filesSrc.length) { grunt.log.error('No test files to run'); return; } var mochaPath = getMochaPath(); var options = this.options(defaultOptions()); var testsDir = grunt.file.isDir(this.filesSrc[0]) ? this.filesSrc[0] : path.dirname(this.filesSrc[0]); var coverageFolder = path.join(options.cwd, options.coverageFolder); var rootFolderForCoverage = options.root ? path.join(options.cwd, options.root) : '.'; var done = this.async(); var args = []; if (options.nodeOptions) { arrayOfStrings(options.nodeOptions, 'options.nodeOptions', function(options){ options.forEach(function(nodeOption){ args.push(nodeOption); }); }) } if (!options.scriptPath) { options.scriptPath = getIstanbulPath(); } if (options.harmony) { args.push('--harmony'); } args.push(options.scriptPath); // ie. node ./node_modules/istanbul/lib/cli.js or another script name args.push('cover'); // node <scriptPath> cover if (options.excludes) { arrayOfStrings(options.excludes, 'options.excludes', function(options){ options.forEach(function (excluded) { args.push('-x'); args.push(excluded); }); }) } if (options.includes) { arrayOfStrings(options.includes, 'options.includes', function(options){ options.forEach(function (included) { args.push('-i'); args.push(included); }); }) } args.push('--dir', coverageFolder); // node ./node_modules/istanbul/cli.js --dir=coverage if (options.root) { args.push('--root', rootFolderForCoverage); } if (options.print) { args.push('--print', options.print); } options.reportFormats.forEach(function (format) { args.push('--report', format); }); if (options.istanbulOptions) { arrayOfStrings(options.istanbulOptions, 'options.istanbulOptions', function(options){ options.forEach(function (opt) { args.push(opt); }); }) } args.push(mochaPath); // node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha args.push('--'); // node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- if (grunt.file.exists(options.cwd, testsDir, 'mocha.opts')) { if ( options.require.length || options.globals.length || options.ui || options.reporter || options.timeout || options.slow || options.grep || options.mask || options.noColors ) { grunt.log.warn('Warning: mocha.opts exists, but overwriting with options'); } } if (options.timeout) { args.push('--timeout'); args.push(options.timeout); } if (options.require) { arrayOfStrings(options.require, 'options.require', function(options){ options.forEach(function (require) { grunt.file.expand({nonull: true}, require).forEach(function(expanded){ args.push('--require'); args.push(expanded); }) }); }); } if (options.ui) { args.push('--ui'); args.push(options.ui); } if (options.noColors) { args.push('--no-colors'); } if (options.reporter) { args.push('--reporter'); args.push(options.reporter); } if (options.globals) { arrayOfStrings(options.globals, 'options.globals', function(options){ args.push('--globals'); args.push(options.join(',')); }); } if (options.slow) { args.push('--slow'); args.push(options.slow); } if (options.grep) { args.push('--grep'); args.push(options.grep); } if (options.recursive) { args.push('--recursive'); } var masked = this.filesSrc; if (options.mask) { masked = masked.map(function (file) { return path.join(grunt.file.isDir(file) ? file : path.dirname(file), options.mask); }); } if (options.mochaOptions) { arrayOfStrings(options.mochaOptions, 'options.mochaOptions', function(options){ options.forEach(function (opt) { args.push(opt); }); }) } args = args.concat(masked); grunt.verbose.ok('Will execute:', options.nodeExec + ' ' + args.join(' ')); if (!options.dryRun) { grunt.util.spawn({ cmd: options.nodeExec, args: args, opts: { env: process.env, cwd: options.cwd, stdio: options.quiet ? 'ignore' : 'inherit' } }, function (err, result) { if (err) { grunt.log.error(result); done(false); return; } executeCheck(function (err, result) { if (!err) { if (options.coverage) { var coverage = grunt.file.read(path.join(coverageFolder, 'lcov.info')); grunt.event.emit('coverage', coverage, function (d) { grunt.log.ok(result || 'Done. Check coverage folder.'); done(d); }); } else { grunt.log.ok(result || 'Done. Check coverage folder.'); done(); } } else { done(err); } }, coverageFolder, options); }); } else { executeCheck(function (err, would) { grunt.log.ok('Would execute:', options.nodeExec + ' ' + args.join(' ')); would && grunt.log.ok(would); }, coverageFolder, options); done(); } }); };