From 99dbbb3a36c12770686f59fa3ff26fbbdc991e8d Mon Sep 17 00:00:00 2001 From: "Benjamin E. Coe" Date: Tue, 13 Sep 2016 09:52:40 -0700 Subject: [PATCH] feat: refactored config to fix precedence of config vs. args (#388) * feat: refactored config to fix precedence of config vs. args see #379 * fix: address standard nits * fix: remove cruft from package.json * fix: address @mourner's code review --- bin/nyc.js | 234 ++++----------------------------- bin/wrap.js | 24 ++-- index.js | 35 ++--- lib/config-util.js | 196 +++++++++++++++++++++++++++ test/fixtures/cli/package.json | 5 +- test/src/nyc-bin.js | 100 ++++++++------ test/src/nyc-test.js | 151 ++++++++------------- 7 files changed, 357 insertions(+), 388 deletions(-) create mode 100644 lib/config-util.js diff --git a/bin/nyc.js b/bin/nyc.js index 1f74661fe..4b0bff0be 100755 --- a/bin/nyc.js +++ b/bin/nyc.js @@ -1,5 +1,5 @@ #!/usr/bin/env node -var arrify = require('arrify') +var configUtil = require('../lib/config-util') var foreground = require('foreground-child') var NYC try { @@ -10,68 +10,44 @@ try { var processArgs = require('../lib/process-args') var sw = require('spawn-wrap') -var testExclude = require('test-exclude') var wrapper = require.resolve('./wrap.js') -var Yargs = require('yargs/yargs') -var yargs = decorateYargs(buildYargs()) -var argv = yargs.parse(processArgs.hideInstrumenteeArgs()) +// parse configuration and command-line arguments; +// we keep these values in a few different forms, +// used in the various execution contexts of nyc: +// reporting, instrumenting subprocesses, etc. +var yargs = configUtil.decorateYargs(configUtil.buildYargs()) +var instrumenterArgs = processArgs.hideInstrumenteeArgs() +var argv = yargs.parse(instrumenterArgs) +var config = configUtil.loadConfig(instrumenterArgs) if (argv._[0] === 'report') { // run a report. process.env.NYC_CWD = process.cwd() - report(argv) + report(config) } else if (argv._[0] === 'check-coverage') { - checkCoverage(argv) + checkCoverage(config) } else if (argv._[0] === 'instrument') { // look in lib/commands/instrument.js for logic. } else if (argv._.length) { - // wrap subprocesses and execute argv[1] - argv.require = arrify(argv.require) - argv.extension = arrify(argv.extension) - argv.exclude = arrify(argv.exclude) - argv.include = arrify(argv.include) - // if instrument is set to false, // enable a noop instrumenter. - if (!argv.instrument) argv.instrumenter = './lib/instrumenters/noop' - else argv.instrumenter = './lib/instrumenters/istanbul' + if (!config.instrument) config.instrumenter = './lib/instrumenters/noop' + else config.instrumenter = './lib/instrumenters/istanbul' - var nyc = (new NYC({ - require: argv.require, - include: argv.include, - exclude: argv.exclude, - sourceMap: !!argv.sourceMap, - instrumenter: argv.instrumenter, - hookRunInContext: argv.hookRunInContext, - showProcessTree: argv.showProcessTree - })) + var nyc = (new NYC(config)) nyc.reset() - if (argv.all) nyc.addAllFiles() + if (config.all) nyc.addAllFiles() var env = { - NYC_CWD: process.cwd(), NYC_CACHE: argv.cache ? 'enable' : 'disable', - NYC_SOURCE_MAP: argv.sourceMap ? 'enable' : 'disable', - NYC_INSTRUMENTER: argv.instrumenter, - NYC_HOOK_RUN_IN_CONTEXT: argv.hookRunInContext ? 'enable' : 'disable', - NYC_SHOW_PROCESS_TREE: argv.showProcessTree ? 'enable' : 'disable', + NYC_CONFIG: JSON.stringify(config), + NYC_CWD: process.cwd(), NYC_ROOT_ID: nyc.rootId, - BABEL_DISABLE_CACHE: 1 - } - if (argv.require.length) { - env.NYC_REQUIRE = argv.require.join(',') - } - if (argv.extension.length) { - env.NYC_EXTENSION = argv.extension.join(',') - } - if (argv.exclude.length) { - env.NYC_EXCLUDE = argv.exclude.join(':') - } - if (argv.include.length) { - env.NYC_INCLUDE = argv.include.join(':') + BABEL_DISABLE_CACHE: 1, + NYC_INSTRUMENTER: config.instrumenter } sw([wrapper], env) @@ -82,17 +58,17 @@ if (argv._[0] === 'report') { foreground(processArgs.hideInstrumenterArgs( // use the same argv descrption, but don't exit // for flags like --help. - buildYargs().parse(process.argv.slice(2)) + configUtil.buildYargs().parse(process.argv.slice(2)) ), function (done) { var mainChildExitCode = process.exitCode - if (argv.checkCoverage) { - checkCoverage(argv) + if (config.checkCoverage) { + checkCoverage(config) process.exitCode = process.exitCode || mainChildExitCode - if (!argv.silent) report(argv) + if (!config.silent) report(config) return done() } else { - if (!argv.silent) report(argv) + if (!config.silent) report(config) return done() } }) @@ -104,12 +80,7 @@ if (argv._[0] === 'report') { function report (argv) { process.env.NYC_CWD = process.cwd() - var nyc = new NYC({ - reporter: argv.reporter, - reportDir: argv.reportDir, - tempDirectory: argv.tempDirectory, - showProcessTree: argv.showProcessTree - }) + var nyc = new NYC(argv) nyc.report() } @@ -123,158 +94,3 @@ function checkCoverage (argv, cb) { statements: argv.statements }) } - -function buildYargs () { - return Yargs([]) - .usage('$0 [command] [options]\n\nrun your tests with the nyc bin to instrument them with coverage') - .command('report', 'run coverage report for .nyc_output', function (yargs) { - return yargs - .usage('$0 report [options]') - .option('reporter', { - alias: 'r', - describe: 'coverage reporter(s) to use', - default: 'text' - }) - .option('report-dir', { - describe: 'directory to output coverage reports in', - default: 'coverage' - }) - .option('temp-directory', { - describe: 'directory from which coverage JSON files are read', - default: './.nyc_output' - }) - .option('show-process-tree', { - describe: 'display the tree of spawned processes', - default: false, - type: 'boolean' - }) - .example('$0 report --reporter=lcov', 'output an HTML lcov report to ./coverage') - }) - .command('check-coverage', 'check whether coverage is within thresholds provided', function (yargs) { - return yargs - .usage('$0 check-coverage [options]') - .option('branches', { - default: 0, - description: 'what % of branches must be covered?' - }) - .option('functions', { - default: 0, - description: 'what % of functions must be covered?' - }) - .option('lines', { - default: 90, - description: 'what % of lines must be covered?' - }) - .option('statements', { - default: 0, - description: 'what % of statements must be covered?' - }) - .example('$0 check-coverage --lines 95', "check whether the JSON in nyc's output folder meets the thresholds provided") - }) - .option('reporter', { - alias: 'r', - describe: 'coverage reporter(s) to use', - default: 'text' - }) - .option('report-dir', { - describe: 'directory to output coverage reports in', - default: 'coverage' - }) - .option('silent', { - alias: 's', - default: false, - type: 'boolean', - describe: "don't output a report after tests finish running" - }) - .option('all', { - alias: 'a', - default: false, - type: 'boolean', - describe: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)' - }) - .option('exclude', { - alias: 'x', - default: testExclude.defaultExclude, - describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded' - }) - .option('include', { - alias: 'n', - default: [], - describe: 'a list of specific files that should be covered, glob patterns are supported' - }) - .option('require', { - alias: 'i', - default: [], - describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.' - }) - .option('cache', { - alias: 'c', - default: false, - type: 'boolean', - describe: 'cache instrumentation results for improved performance' - }) - .option('extension', { - alias: 'e', - default: [], - describe: 'a list of extensions that nyc should handle in addition to .js' - }) - .option('check-coverage', { - type: 'boolean', - default: false, - describe: 'check whether coverage is within thresholds provided' - }) - .option('branches', { - default: 0, - description: 'what % of branches must be covered?' - }) - .option('functions', { - default: 0, - description: 'what % of functions must be covered?' - }) - .option('lines', { - default: 90, - description: 'what % of lines must be covered?' - }) - .option('statements', { - default: 0, - description: 'what % of statements must be covered?' - }) - .option('source-map', { - default: true, - type: 'boolean', - description: 'should nyc detect and handle source maps?' - }) - .option('instrument', { - default: true, - type: 'boolean', - description: 'should nyc handle instrumentation?' - }) - .option('hook-run-in-context', { - default: true, - type: 'boolean', - description: 'should nyc wrap vm.runInThisContext?' - }) - .option('show-process-tree', { - describe: 'display the tree of spawned processes', - default: false, - type: 'boolean' - }) - .pkgConf('nyc', process.cwd()) - .example('$0 npm test', 'instrument your tests with coverage') - .example('$0 --require babel-core/register npm test', 'instrument your tests with coverage and babel') - .example('$0 report --reporter=text-lcov', 'output lcov report after running your tests') - .epilog('visit https://git.io/voHar for list of available reporters') - .boolean('help') - .boolean('h') - .boolean('version') -} - -// decorate yargs with all the actions -// that would make it exit: help, version, command. -function decorateYargs (yargs) { - return yargs - .help('h') - .alias('h', 'help') - .version() - .command(require('../lib/commands/instrument')) -} diff --git a/bin/wrap.js b/bin/wrap.js index c53925343..d64aceb1a 100644 --- a/bin/wrap.js +++ b/bin/wrap.js @@ -9,20 +9,14 @@ try { var parentPid = process.env.NYC_PARENT_PID || '0' process.env.NYC_PARENT_PID = process.pid -;(new NYC({ - require: process.env.NYC_REQUIRE ? process.env.NYC_REQUIRE.split(',') : [], - extension: process.env.NYC_EXTENSION ? process.env.NYC_EXTENSION.split(',') : [], - exclude: process.env.NYC_EXCLUDE ? process.env.NYC_EXCLUDE.split(':') : [], - include: process.env.NYC_INCLUDE ? process.env.NYC_INCLUDE.split(':') : [], - enableCache: process.env.NYC_CACHE === 'enable', - sourceMap: process.env.NYC_SOURCE_MAP === 'enable', - instrumenter: process.env.NYC_INSTRUMENTER, - hookRunInContext: process.env.NYC_HOOK_RUN_IN_CONTEXT === 'enable', - showProcessTree: process.env.NYC_SHOW_PROCESS_TREE === 'enable', - _processInfo: { - ppid: parentPid, - root: process.env.NYC_ROOT_ID - } -})).wrap() +var config = {} +if (process.env.NYC_CONFIG) config = JSON.parse(process.env.NYC_CONFIG) +config.enableCache = process.env.NYC_CACHE === 'enable' +config._processInfo = { + ppid: parentPid, + root: process.env.NYC_ROOT_ID +} + +;(new NYC(config)).wrap() sw.runMain() diff --git a/index.js b/index.js index 1517a5528..d64c3787f 100755 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ /* global __coverage__ */ +var arrify = require('arrify') var fs = require('fs') var glob = require('glob') var libCoverage = require('istanbul-lib-coverage') @@ -13,14 +14,11 @@ var path = require('path') var rimraf = require('rimraf') var onExit = require('signal-exit') var resolveFrom = require('resolve-from') -var arrify = require('arrify') var convertSourceMap = require('convert-source-map') var md5hex = require('md5-hex') var findCacheDir = require('find-cache-dir') var js = require('default-require-extensions/js') -var pkgUp = require('pkg-up') var testExclude = require('test-exclude') -var yargs = require('yargs') var ProcessInfo try { @@ -34,17 +32,16 @@ if (/index\.covered\.js$/.test(__filename)) { require('./lib/self-coverage-helper') } -function NYC (opts) { - var config = this._loadConfig(opts || {}) +function NYC (config) { + config = config || {} - this._istanbul = config.istanbul this.subprocessBin = config.subprocessBin || path.resolve(__dirname, './bin/nyc.js') this._tempDirectory = config.tempDirectory || './.nyc_output' this._instrumenterLib = require(config.instrumenter || './lib/instrumenters/istanbul') - this._reportDir = config.reportDir - this._sourceMap = config.sourceMap - this._showProcessTree = config.showProcessTree - this.cwd = config.cwd + this._reportDir = config.reportDir || 'coverage' + this._sourceMap = typeof config.sourceMap === 'boolean' ? config.sourceMap : true + this._showProcessTree = config.showProcessTree || false + this.cwd = config.cwd || process.cwd() this.reporter = arrify(config.reporter || 'text') @@ -80,26 +77,10 @@ function NYC (opts) { this.loadedMaps = null this.fakeRequire = null - this.processInfo = new ProcessInfo(opts && opts._processInfo) + this.processInfo = new ProcessInfo(config && config._processInfo) this.rootId = this.processInfo.root || this.generateUniqueID() } -NYC.prototype._loadConfig = function (opts) { - var cwd = opts.cwd || process.env.NYC_CWD || process.cwd() - var pkgPath = pkgUp.sync(cwd) - - if (pkgPath) { - cwd = path.dirname(pkgPath) - } - - opts.cwd = cwd - - return yargs([]) - .pkgConf('nyc', cwd) - .default(opts) - .argv -} - NYC.prototype._createTransform = function (ext) { var _this = this return cachingTransform({ diff --git a/lib/config-util.js b/lib/config-util.js new file mode 100644 index 000000000..b137d599f --- /dev/null +++ b/lib/config-util.js @@ -0,0 +1,196 @@ +var arrify = require('arrify') +var path = require('path') +var pkgUp = require('pkg-up') +var testExclude = require('test-exclude') +var Yargs = require('yargs/yargs') + +var Config = {} + +// load config from a cascade of sources: +// * command line arguments. +// * package.json. +// * .nycrc (coming soon) +Config.loadConfig = function (argv, cwd) { + cwd = cwd || process.env.NYC_CWD || process.cwd() + var pkgPath = pkgUp.sync(cwd) + + if (pkgPath) { + cwd = path.dirname(pkgPath) + } + + var config = Config.buildYargs(cwd) + .default({ + cwd: cwd + }) + .parse(argv || []) + + // post-hoc, we convert several of the + // configuration settings to arrays, providing + // a consistent contract to index.js. + config.require = arrify(config.require) + config.extension = arrify(config.extension) + config.exclude = arrify(config.exclude) + config.include = arrify(config.include) + config.cwd = cwd + + return config +} + +// build a yargs object, omitting any settings +// that would cause the application to exit early. +Config.buildYargs = function (cwd) { + return Yargs([]) + .usage('$0 [command] [options]\n\nrun your tests with the nyc bin to instrument them with coverage') + .command('report', 'run coverage report for .nyc_output', function (yargs) { + return yargs + .usage('$0 report [options]') + .option('reporter', { + alias: 'r', + describe: 'coverage reporter(s) to use', + default: 'text' + }) + .option('report-dir', { + describe: 'directory to output coverage reports in', + default: 'coverage' + }) + .option('temp-directory', { + describe: 'directory from which coverage JSON files are read', + default: './.nyc_output' + }) + .option('show-process-tree', { + describe: 'display the tree of spawned processes', + default: false, + type: 'boolean' + }) + .example('$0 report --reporter=lcov', 'output an HTML lcov report to ./coverage') + }) + .command('check-coverage', 'check whether coverage is within thresholds provided', function (yargs) { + return yargs + .usage('$0 check-coverage [options]') + .option('branches', { + default: 0, + description: 'what % of branches must be covered?' + }) + .option('functions', { + default: 0, + description: 'what % of functions must be covered?' + }) + .option('lines', { + default: 90, + description: 'what % of lines must be covered?' + }) + .option('statements', { + default: 0, + description: 'what % of statements must be covered?' + }) + .example('$0 check-coverage --lines 95', "check whether the JSON in nyc's output folder meets the thresholds provided") + }) + .option('reporter', { + alias: 'r', + describe: 'coverage reporter(s) to use', + default: 'text' + }) + .option('report-dir', { + describe: 'directory to output coverage reports in', + default: 'coverage' + }) + .option('silent', { + alias: 's', + default: false, + type: 'boolean', + describe: "don't output a report after tests finish running" + }) + .option('all', { + alias: 'a', + default: false, + type: 'boolean', + describe: 'whether or not to instrument all files of the project (not just the ones touched by your test suite)' + }) + .option('exclude', { + alias: 'x', + default: testExclude.defaultExclude, + describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded' + }) + .option('include', { + alias: 'n', + default: [], + describe: 'a list of specific files that should be covered, glob patterns are supported' + }) + .option('require', { + alias: 'i', + default: [], + describe: 'a list of additional modules that nyc should attempt to require in its subprocess, e.g., babel-register, babel-polyfill.' + }) + .option('cache', { + alias: 'c', + default: false, + type: 'boolean', + describe: 'cache instrumentation results for improved performance' + }) + .option('extension', { + alias: 'e', + default: [], + describe: 'a list of extensions that nyc should handle in addition to .js' + }) + .option('check-coverage', { + type: 'boolean', + default: false, + describe: 'check whether coverage is within thresholds provided' + }) + .option('branches', { + default: 0, + description: 'what % of branches must be covered?' + }) + .option('functions', { + default: 0, + description: 'what % of functions must be covered?' + }) + .option('lines', { + default: 90, + description: 'what % of lines must be covered?' + }) + .option('statements', { + default: 0, + description: 'what % of statements must be covered?' + }) + .option('source-map', { + default: true, + type: 'boolean', + description: 'should nyc detect and handle source maps?' + }) + .option('instrument', { + default: true, + type: 'boolean', + description: 'should nyc handle instrumentation?' + }) + .option('hook-run-in-context', { + default: true, + type: 'boolean', + description: 'should nyc wrap vm.runInThisContext?' + }) + .option('show-process-tree', { + describe: 'display the tree of spawned processes', + default: false, + type: 'boolean' + }) + .pkgConf('nyc', cwd || process.cwd()) + .example('$0 npm test', 'instrument your tests with coverage') + .example('$0 --require babel-core/register npm test', 'instrument your tests with coverage and babel') + .example('$0 report --reporter=text-lcov', 'output lcov report after running your tests') + .epilog('visit https://git.io/voHar for list of available reporters') + .boolean('help') + .boolean('h') + .boolean('version') +} + +// decorate yargs with all the actions +// that would make it exit: help, version, command. +Config.decorateYargs = function (yargs) { + return yargs + .help('h') + .alias('h', 'help') + .version() + .command(require('../lib/commands/instrument')) +} + +module.exports = Config diff --git a/test/fixtures/cli/package.json b/test/fixtures/cli/package.json index 352055cdf..d67ca669e 100644 --- a/test/fixtures/cli/package.json +++ b/test/fixtures/cli/package.json @@ -1,3 +1,6 @@ { - "private": true + "private": true, + "nyc": { + "reporter": ["text"] + } } diff --git a/test/src/nyc-bin.js b/test/src/nyc-bin.js index e6fe04bed..4f998954e 100644 --- a/test/src/nyc-bin.js +++ b/test/src/nyc-bin.js @@ -222,44 +222,67 @@ describe('the nyc cli', function () { }) }) - it('passes configuration via environment variables', function (done) { - var args = [ - bin, - '--silent', - '--require=mkdirp', - '--include=env.js', - '--exclude=batman.js', - '--extension=.js', - '--cache=true', - '--source-map=true', - process.execPath, - './env.js' - ] - var expected = { - NYC_REQUIRE: 'mkdirp', - NYC_INCLUDE: 'env.js', - NYC_EXCLUDE: 'batman.js', - NYC_EXTENSION: '.js', - NYC_CACHE: 'enable', - NYC_SOURCE_MAP: 'enable', - NYC_INSTRUMENTER: './lib/instrumenters/istanbul' - } + describe('configuration', function () { + it('passes configuration via environment variables', function (done) { + var args = [ + bin, + '--silent', + '--require=mkdirp', + '--include=env.js', + '--exclude=batman.js', + '--extension=.js', + '--cache=true', + '--source-map=true', + process.execPath, + './env.js' + ] + var expected = { + instrumenter: './lib/instrumenters/istanbul', + silent: true, + cache: true, + sourceMap: true + } - var proc = spawn(process.execPath, args, { - cwd: fixturesCLI, - env: env - }) + var proc = spawn(process.execPath, args, { + cwd: fixturesCLI, + env: env + }) - var stdout = '' - proc.stdout.on('data', function (chunk) { - stdout += chunk + var stdout = '' + proc.stdout.on('data', function (chunk) { + stdout += chunk + }) + + proc.on('close', function (code) { + code.should.equal(0) + var env = JSON.parse(stdout) + var config = JSON.parse(env.NYC_CONFIG, null, 2) + config.should.include(expected) + config.include.should.include('env.js') + config.exclude.should.include('batman.js') + config.extension.should.include('.js') + done() + }) }) - proc.on('close', function (code) { - code.should.equal(0) - var env = JSON.parse(stdout) - env.should.include(expected) - done() + it('allows package.json configuration to be overridden with command line args', function (done) { + var args = [bin, '--reporter=text-lcov', process.execPath, './half-covered.js'] + + var proc = spawn(process.execPath, args, { + cwd: fixturesCLI, + env: env + }) + + var stdout = '' + proc.stdout.on('data', function (chunk) { + stdout += chunk + }) + + proc.on('close', function (code) { + code.should.equal(0) + stdout.should.match(/SF:.*half-covered\.js/) + done() + }) }) }) @@ -273,8 +296,10 @@ describe('the nyc cli', function () { './env.js' ] var expected = { - NYC_SOURCE_MAP: 'disable', - NYC_INSTRUMENTER: './lib/instrumenters/noop' + silent: true, + instrument: false, + sourceMap: false, + instrumenter: './lib/instrumenters/noop' } var proc = spawn(process.execPath, args, { @@ -290,7 +315,8 @@ describe('the nyc cli', function () { proc.on('close', function (code) { code.should.equal(0) var env = JSON.parse(stdout) - env.should.include(expected) + var config = JSON.parse(env.NYC_CONFIG, null, 2) + config.should.include(expected) done() }) }) diff --git a/test/src/nyc-test.js b/test/src/nyc-test.js index 2659979da..9657d6a6d 100644 --- a/test/src/nyc-test.js +++ b/test/src/nyc-test.js @@ -3,6 +3,7 @@ require('source-map-support').install() var _ = require('lodash') var ap = require('any-path') +var configUtil = require('../../lib/config-util') var fs = require('fs') var enableCache = false var _NYC @@ -44,51 +45,46 @@ require('tap').mochaGlobals() describe('nyc', function () { describe('cwd', function () { it('sets cwd to process.cwd() if no environment variable is set', function () { - var nyc = new NYC() + var nyc = new NYC(configUtil.loadConfig()) nyc.cwd.should.eql(process.cwd()) }) it('uses NYC_CWD environment variable for cwd if it is set', function () { process.env.NYC_CWD = path.resolve(__dirname, '../fixtures') - - var nyc = new NYC() + var nyc = new NYC(configUtil.loadConfig()) nyc.cwd.should.equal(path.resolve(__dirname, '../fixtures')) }) it('will look upwards for package.json from cwd', function () { - var nyc = new NYC({cwd: __dirname}) + var nyc = new NYC(configUtil.loadConfig([], __dirname)) nyc.cwd.should.eql(path.join(__dirname, '../..')) }) }) describe('config', function () { it("loads 'exclude' patterns from package.json#nyc", function () { - var nyc = new NYC({ - cwd: path.resolve(__dirname, '../fixtures') - }) + var nyc = new NYC(configUtil.loadConfig([], path.resolve(__dirname, '../fixtures'))) nyc.exclude.exclude.length.should.eql(4) }) it("loads 'extension' patterns from package.json#nyc", function () { - var nyc = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-multiple-extensions') - }) + var nyc = new NYC(configUtil.loadConfig([], path.resolve(__dirname, '../fixtures/conf-multiple-extensions'))) nyc.extensions.length.should.eql(3) }) it("ignores 'include' option if it's falsy or []", function () { - var nyc1 = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-empty') - }) + var nyc1 = new NYC(configUtil.loadConfig( + [], + path.resolve(__dirname, '../fixtures/conf-empty') + )) nyc1.exclude.include.should.equal(false) var nyc2 = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-empty'), include: [] }) @@ -96,18 +92,13 @@ describe('nyc', function () { }) it("ignores 'exclude' option if it's falsy", function () { - var nyc1 = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-empty') - }) + var nyc1 = new NYC(configUtil.loadConfig([], path.resolve(__dirname, '../fixtures/conf-empty'))) nyc1.exclude.exclude.length.should.eql(7) }) it("allows for empty 'exclude'", function () { - var nyc2 = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-empty'), - exclude: [] - }) + var nyc2 = new NYC({exclude: []}) nyc2.exclude.exclude.length.should.eql(0) }) @@ -115,16 +106,13 @@ describe('nyc', function () { describe('shouldInstrumentFile', function () { it('should exclude appropriately with defaults', function () { - var nyc = new NYC({ - cwd: '/cwd/', - exclude: [ - '**/node_modules/**', - 'test/**', - 'test{,-*}.js', - '**/*.test.js', - '**/__tests__/**' - ] - }) + var nyc = new NYC(configUtil.loadConfig([ + '--exclude=**/node_modules/**', + '--exclude=test/**', + '--exclude=test{,-*}.js', + '--exclude=**/*.test.js', + '--exclude=**/__tests__/**' + ], '/cwd')) // nyc always excludes "node_modules/**" nyc.exclude.shouldInstrument('/cwd/foo', 'foo').should.equal(true) @@ -141,9 +129,7 @@ describe('nyc', function () { }) it('should exclude appropriately with config.exclude', function () { - var nyc = new NYC({ - cwd: fixtures - }) + var nyc = new NYC(configUtil.loadConfig([], fixtures)) // fixtures/package.json configures excludes: "blarg", "blerg" nyc.exclude.shouldInstrument('blarg', 'blarg').should.equal(false) @@ -154,43 +140,31 @@ describe('nyc', function () { }) it('should exclude outside of the current working directory', function () { - var nyc = new NYC({ - cwd: '/cwd/foo/' - }) + var nyc = new NYC(configUtil.loadConfig([], '/cwd/foo/')) nyc.exclude.shouldInstrument('/cwd/bar', '../bar').should.equal(false) }) it('should not exclude if the current working directory is inside node_modules', function () { - var nyc = new NYC({ - cwd: '/cwd/node_modules/foo/' - }) + var nyc = new NYC(configUtil.loadConfig([], '/cwd/node_modules/foo/')) nyc.exclude.shouldInstrument('/cwd/node_modules/foo/bar', './bar').should.equal(true) nyc.exclude.shouldInstrument('/cwd/node_modules/foo/bar', '.\\bar').should.equal(true) }) it('allows files to be explicitly included, rather than excluded', function () { - var nyc = new NYC({ - cwd: '/cwd/', - include: 'foo.js' - }) + var nyc = new NYC(configUtil.loadConfig(['--include=foo.js'], '/cwd/')) nyc.exclude.shouldInstrument('/cwd/foo.js', 'foo.js').should.equal(true) nyc.exclude.shouldInstrument('/cwd/index.js', 'index.js').should.equal(false) }) it('exclude overrides include', function () { - var nyc = new NYC({ - cwd: '/cwd/', - include: [ - 'foo.js', - 'test.js' - ], - exclude: [ - '**/node_modules/**', - 'test/**', - 'test{,-*}.js' - ] - }) + var nyc = new NYC(configUtil.loadConfig([ + '--include=foo.js', + '--include=test.js', + '--exclude=**/node_modules/**', + '--exclude=test/**', + '--exclude=test{,-*}.js' + ], '/cwd/')) nyc.exclude.shouldInstrument('/cwd/foo.js', 'foo.js').should.equal(true) nyc.exclude.shouldInstrument('/cwd/test.js', 'test.js').should.equal(false) @@ -199,9 +173,7 @@ describe('nyc', function () { describe('wrap', function () { it('wraps modules with coverage counters when they are required', function () { - var nyc = new NYC({ - cwd: process.cwd() - }) + var nyc = new NYC(configUtil.loadConfig()) nyc.reset() nyc.wrap() @@ -218,9 +190,7 @@ describe('nyc', function () { // the `require` call to istanbul is deferred, loaded here so it doesn't mess with the hooks callCount require('istanbul-lib-instrument') - var nyc = new NYC({ - cwd: process.cwd() - }) + var nyc = new NYC(configUtil.loadConfig()) nyc.reset() nyc.wrap() @@ -237,9 +207,9 @@ describe('nyc', function () { describe('compile handlers for custom extensions are assigned', function () { it('assigns a function to custom extensions', function () { - var nyc = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-multiple-extensions') - }) + var nyc = new NYC(configUtil.loadConfig([], + path.resolve(__dirname, '../fixtures/conf-multiple-extensions') + )) nyc.reset() nyc.wrap() @@ -254,9 +224,9 @@ describe('nyc', function () { // the `require` call to istanbul is deferred, loaded here so it doesn't mess with the hooks callCount require('istanbul-lib-instrument') - var nyc = new NYC({ - cwd: path.resolve(__dirname, '../fixtures/conf-multiple-extensions') - }) + var nyc = new NYC(configUtil.loadConfig([], + path.resolve(__dirname, '../fixtures/conf-multiple-extensions') + )) sinon.spy(nyc, '_handleJs') @@ -272,9 +242,7 @@ describe('nyc', function () { }) function testSignal (signal, done) { - var nyc = (new NYC({ - cwd: fixtures - })) + var nyc = (new NYC(configUtil.loadConfig([], fixtures))) var proc = spawn(process.execPath, [bin, './' + signal + '.js'], { cwd: fixtures, @@ -302,9 +270,7 @@ describe('nyc', function () { }) it('does not output coverage for files that have not been included, by default', function (done) { - var nyc = (new NYC({ - cwd: process.cwd() - })) + var nyc = (new NYC(configUtil.loadConfig([], process.cwd()))) nyc.wrap() nyc.reset() @@ -318,12 +284,9 @@ describe('nyc', function () { describe('report', function () { it('allows coverage report to be output in an alternative directory', function (done) { - var reporters = ['lcov'] - var nyc = new NYC({ - cwd: process.cwd(), - reporter: reporters, - reportDir: './alternative-report' - }) + var nyc = new NYC(configUtil.loadConfig( + ['--report-dir=./alternative-report', '--reporter=lcov'] + )) nyc.reset() var proc = spawn(process.execPath, ['./test/fixtures/child-1.js'], { @@ -343,9 +306,7 @@ describe('nyc', function () { describe('addAllFiles', function () { it('outputs an empty coverage report for all files that are not excluded', function (done) { - var nyc = new NYC({ - cwd: fixtures - }) + var nyc = new NYC(configUtil.loadConfig([], fixtures)) nyc.reset() nyc.addAllFiles() @@ -363,9 +324,7 @@ describe('nyc', function () { it('outputs an empty coverage report for multiple configured extensions', function (done) { var cwd = path.resolve(fixtures, './conf-multiple-extensions') - var nyc = new NYC({ - cwd: cwd - }) + var nyc = new NYC(configUtil.loadConfig([], cwd)) nyc.reset() nyc.addAllFiles() @@ -390,9 +349,7 @@ describe('nyc', function () { }) it('tracks coverage appropriately once the file is required', function (done) { - var nyc = (new NYC({ - cwd: fixtures - })) + var nyc = (new NYC(configUtil.loadConfig([], fixtures))) nyc.reset() nyc.wrap() @@ -420,10 +377,7 @@ describe('nyc', function () { 'utf-8' ) - var nyc = (new NYC({ - cwd: fixtures, - require: './test/fixtures/transpile-hook' - })) + var nyc = (new NYC(configUtil.loadConfig(['--require', './test/fixtures/transpile-hook'], fixtures))) nyc.reset() nyc.addAllFiles() @@ -449,11 +403,10 @@ describe('nyc', function () { 'utf-8' ) - var nyc = (new NYC({ - cwd: fixtures, - require: './test/fixtures/transpile-hook', - extension: ['.whatever'] - })) + var nyc = (new NYC(configUtil.loadConfig([ + '--require=./test/fixtures/transpile-hook', + '--extension=.whatever' + ], fixtures))) nyc.reset() nyc.addAllFiles() @@ -473,7 +426,7 @@ describe('nyc', function () { describe('cache', function () { it('handles collisions', function (done) { - var nyc = new NYC({cwd: fixtures}) + var nyc = new NYC(configUtil.loadConfig([], fixtures)) nyc.clearCache() var args = [bin, process.execPath, './cache-collision-runner.js']