diff --git a/bin/nyc.js b/bin/nyc.js index 3760dbc7d..5f295abb7 100755 --- a/bin/nyc.js +++ b/bin/nyc.js @@ -43,6 +43,7 @@ async function main () { NYC_CWD: process.cwd() } + /* istanbul ignore else */ if (argv['babel-cache'] === false) { // babel's cache interferes with some configurations, so is // disabled by default. opt in by setting babel-cache=true. @@ -103,6 +104,6 @@ async function main () { /* istanbul ignore next: the error branch should be unreachable */ main().catch(error => { - console.log('nyc error:', error) + console.error(error.message) process.exit(1) }) diff --git a/index.js b/index.js index c51bf7508..92e22d5a2 100755 --- a/index.js +++ b/index.js @@ -48,8 +48,7 @@ function coverageFinder () { class NYC { constructor (config) { - config = config || {} - this.config = config + this.config = { ...config } this.subprocessBin = config.subprocessBin || path.resolve(__dirname, './bin/nyc.js') this._tempDirectory = config.tempDirectory || config.tempDir || './.nyc_output' @@ -151,7 +150,7 @@ class NYC { compact: this.config.compact, preserveComments: this.config.preserveComments, esModules: this.config.esModules, - plugins: this.config.parserPlugins + parserPlugins: this.config.parserPlugins }) } @@ -365,7 +364,6 @@ class NYC { writeCoverageFile () { var coverage = coverageFinder() - if (!coverage) return // Remove any files that should be excluded but snuck into the coverage Object.keys(coverage).forEach(function (absFile) { diff --git a/lib/commands/instrument.js b/lib/commands/instrument.js index 256e40db4..f88cccfd0 100644 --- a/lib/commands/instrument.js +++ b/lib/commands/instrument.js @@ -1,6 +1,7 @@ const NYC = require('../../index.js') const path = require('path') const { promisify } = require('util') +const resolveFrom = require('resolve-from') const rimraf = promisify(require('rimraf')) const { cliWrapper, setupOptions } = require('./helpers.js') @@ -49,5 +50,12 @@ exports.handler = cliWrapper(async argv => { } const nyc = new NYC(argv) + if (!argv.useSpawnWrap) { + nyc.require.forEach(requireModule => { + const mod = resolveFrom.silent(nyc.cwd, requireModule) || requireModule + require(mod) + }) + } + await nyc.instrumentAllFiles(argv.input, argv.output) }) diff --git a/lib/fs-promises.js b/lib/fs-promises.js index c99316a40..b67ebb1c2 100644 --- a/lib/fs-promises.js +++ b/lib/fs-promises.js @@ -44,6 +44,7 @@ const fns = [ 'writeFile' ] fns.forEach(fn => { + /* istanbul ignore else: all functions exist on OSX */ if (fs[fn]) { module.exports[fn] = promisify(fs[fn]) } diff --git a/lib/instrumenters/istanbul.js b/lib/instrumenters/istanbul.js index 29462181b..1793f0c79 100644 --- a/lib/instrumenters/istanbul.js +++ b/lib/instrumenters/istanbul.js @@ -5,9 +5,6 @@ function InstrumenterIstanbul (options) { const convertSourceMap = require('convert-source-map') const mergeSourceMap = require('merge-source-map') - const { plugins } = options - const configPlugins = plugins ? { plugins } : {} - const instrumenter = createInstrumenter({ autoWrap: true, coverageVariable: '__coverage__', @@ -17,7 +14,7 @@ function InstrumenterIstanbul (options) { produceSourceMap: options.produceSourceMap, ignoreClassMethods: options.ignoreClassMethods, esModules: options.esModules, - ...configPlugins + parserPlugins: options.parserPlugins }) return { diff --git a/lib/wrap.js b/lib/wrap.js index cb3213340..3f18f8a29 100644 --- a/lib/wrap.js +++ b/lib/wrap.js @@ -1,9 +1,10 @@ const NYC = require('../index.js') -let config = {} -if (process.env.NYC_CONFIG) { - config = JSON.parse(process.env.NYC_CONFIG) -} +const config = JSON.parse( + process.env.NYC_CONFIG || + /* istanbul ignore next */ '{}' +) + config.isChildProcess = true config._processInfo = { @@ -18,11 +19,7 @@ if (process.env.NYC_PROCESSINFO_EXTERNAL_ID) { } if (process.env.NYC_CONFIG_OVERRIDE) { - const override = JSON.parse(process.env.NYC_CONFIG_OVERRIDE) - config = { - ...config, - ...override - } + Object.assign(config, JSON.parse(process.env.NYC_CONFIG_OVERRIDE)) process.env.NYC_CONFIG = JSON.stringify(config) } diff --git a/nyc.config.js b/nyc.config.js new file mode 100644 index 000000000..eedda3dd0 --- /dev/null +++ b/nyc.config.js @@ -0,0 +1,22 @@ +'use strict' + +const isWindows = require('is-windows')() + +module.exports = { + exclude: [ + 'coverage', + 'self-coverage', + 'test/fixtures/coverage.js', + 'test/build/*', + 'test/src/*', + 'test/nyc.js', + 'test/process-args.js', + 'test/fixtures/_generateCoverage.js' + ], + /* Unknown why we don't get 100% coverage on Windows. */ + 'check-coverage': !isWindows, + branches: 100, + functions: 100, + lines: 100, + statements: 100 +} diff --git a/package.json b/package.json index ad9ae4d09..8a68cbb07 100644 --- a/package.json +++ b/package.json @@ -22,19 +22,6 @@ "bin/*.js", "lib/**/*.js" ], - "nyc": { - "exclude": [ - "node_modules", - "coverage", - "self-coverage", - "test/fixtures/coverage.js", - "test/build/*", - "test/src/*", - "test/nyc.js", - "test/process-args.js", - "test/fixtures/_generateCoverage.js" - ] - }, "standard": { "ignore": [ "**/fixtures/**", diff --git a/tap-snapshots/test-nyc-integration.js-TAP.test.js b/tap-snapshots/test-nyc-integration.js-TAP.test.js index b026b05b6..7e4f26dad 100644 --- a/tap-snapshots/test-nyc-integration.js-TAP.test.js +++ b/tap-snapshots/test-nyc-integration.js-TAP.test.js @@ -930,6 +930,16 @@ exports[`test/nyc-integration.js TAP reports error if input is not a directory > ` +exports[`test/nyc-integration.js TAP run-in-context provide coverage for vm.runInContext > stdout 1`] = ` +---------------|---------|----------|---------|---------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +---------------|---------|----------|---------|---------|------------------- +All files | 100 | 100 | 100 | 100 | + in-context.js | 100 | 100 | 100 | 100 | +---------------|---------|----------|---------|---------|------------------- + +` + exports[`test/nyc-integration.js TAP setting instrument to "false" configures noop instrumenter > must match snapshot 1`] = ` [ [ diff --git a/test/fixtures/hooks/run-in-context.js b/test/fixtures/hooks/run-in-context.js new file mode 100644 index 000000000..653a45dac --- /dev/null +++ b/test/fixtures/hooks/run-in-context.js @@ -0,0 +1,9 @@ +'use strict' +const path = require('path') +const vm = require('vm') + +vm.runInContext( + '(() => 10)();', + vm.createContext({}), + path.resolve(__dirname, 'in-context.js') +) diff --git a/test/fixtures/nyc.config.js b/test/fixtures/nyc.config.js new file mode 100644 index 000000000..f925162f5 --- /dev/null +++ b/test/fixtures/nyc.config.js @@ -0,0 +1,4 @@ +'use strict' + +// This just blocks fixtures from seeing the root nyc.config.js +module.exports = {} diff --git a/test/fixtures/parser-plugins/no-plugins.json b/test/fixtures/parser-plugins/no-plugins.json new file mode 100644 index 000000000..e95c94f2e --- /dev/null +++ b/test/fixtures/parser-plugins/no-plugins.json @@ -0,0 +1,3 @@ +{ + "parser-plugins": [] +} diff --git a/test/fixtures/parser-plugins/package.json b/test/fixtures/parser-plugins/package.json new file mode 100644 index 000000000..d655f2ed8 --- /dev/null +++ b/test/fixtures/parser-plugins/package.json @@ -0,0 +1,7 @@ +{ + "nyc": { + "parser-plugins": [ + "v8intrinsic" + ] + } +} diff --git a/test/fixtures/parser-plugins/v8.js b/test/fixtures/parser-plugins/v8.js new file mode 100644 index 000000000..74c572a08 --- /dev/null +++ b/test/fixtures/parser-plugins/v8.js @@ -0,0 +1,2 @@ +function fn() {} +%GetOptimizationStatus(fn) diff --git a/test/nyc-integration.js b/test/nyc-integration.js index dc630afc5..5fd43a199 100644 --- a/test/nyc-integration.js +++ b/test/nyc-integration.js @@ -167,6 +167,16 @@ t.test('hooks provide coverage for requireJS and AMD modules', t => testSuccess( cwd: path.resolve(__dirname, './fixtures/hooks') })) +t.test('run-in-context provide coverage for vm.runInContext', t => testSuccess(t, { + args: [ + '--hook-run-in-context', + '--hook-require=false', + process.execPath, + './run-in-context.js' + ], + cwd: path.resolve(__dirname, './fixtures/hooks') +})) + t.test('does not interpret args intended for instrumented bin', async t => { const { status, stderr, stdout } = await runNYC({ tempDir: t.tempDir, @@ -215,6 +225,18 @@ t.test('nyc instrument single file to console', async t => { t.match(originalText.stdout, `path:${JSON.stringify(path.resolve(fixturesCLI, 'half-covered.js'))}`) }) +t.test('nyc instrument disabled instrument', async t => { + const { status, stderr, stdout } = await runNYC({ + tempDir: t.tempDir, + args: ['instrument', '--instrument=false', 'half-covered.js'] + }) + + t.is(status, 0) + t.is(stderr, '') + t.match(stdout, 'var a = 0') + t.notMatch(stdout, 'cov_') +}) + t.test('nyc instrument a directory of files', async t => { const { status, stderr, originalText } = await runNYC({ tempDir: t.tempDir, @@ -570,7 +592,6 @@ t.test('combines multiple coverage reports', async t => { }) const mergedCoverage = require('./fixtures/cli/coverage') - console.log(Object.keys(mergedCoverage)) // the combined reports should have 100% function // branch and statement coverage. t.strictDeepEqual( @@ -600,3 +621,48 @@ t.test('--all instruments unknown extensions as js', t => testSuccess(t, { cwd: path.resolve(fixturesCLI, '../conf-multiple-extensions'), args: ['--all', process.execPath, './run.js'] })) + +t.test('instrument with invalid --require fails when using node-preload', async t => { + const { status, stderr, stdout } = await runNYC({ + tempDir: t.tempDir, + args: [ + '--require=@istanbuljs/this-module-does-not-exist', + 'instrument', + './skip-full.js' + ] + }) + + t.is(status, 1) + t.match(stderr, /Cannot find module '@istanbuljs\/this-module-does-not-exist'/) + t.is(stdout, '') +}) + +t.test('invalid --require fails when using node-preload', async t => { + const { status, stderr, stdout } = await runNYC({ + tempDir: t.tempDir, + args: [ + '--require=@istanbuljs/this-module-does-not-exist', + './skip-full.js' + ] + }) + + t.is(status, 1) + t.match(stderr, /Cannot find module '@istanbuljs\/this-module-does-not-exist'/) + t.is(stdout, '') +}) + +t.test('invalid --require fails when using spawn-wrap', async t => { + const { status, stderr, stdout } = await runNYC({ + tempDir: t.tempDir, + args: [ + '--use-spawn-wrap=true', + '--require=@istanbuljs/this-module-does-not-exist', + 'instrument', + './skip-full.js' + ] + }) + + t.is(status, 1) + t.match(stderr, /Cannot find module '@istanbuljs\/this-module-does-not-exist'/) + t.is(stdout, '') +}) diff --git a/test/parser-plugins.js b/test/parser-plugins.js new file mode 100644 index 000000000..c375e6121 --- /dev/null +++ b/test/parser-plugins.js @@ -0,0 +1,29 @@ +'use strict' + +const path = require('path') + +const t = require('tap') + +const { runNYC } = require('./helpers') + +const cwd = path.resolve(__dirname, './fixtures/parser-plugins') + +t.test('parser plugin set', async t => { + const { status, stdout, stderr } = await runNYC({ + args: ['instrument', 'v8.js'], + cwd + }) + t.strictEqual(status, 0) + t.strictEqual(stderr, '') + t.match(stdout, /function cov_/) +}) + +t.test('parser plugin unset', async t => { + const { status, stdout, stderr } = await runNYC({ + args: ['instrument', '--nycrc-path=no-plugins.json', 'v8.js'], + cwd + }) + t.strictEqual(status, 0) + t.strictEqual(stderr, '') + t.notMatch(stdout, /function cov_/) +}) diff --git a/test/process-args.js b/test/process-args.js index 4b0cf4335..ca3a37db5 100644 --- a/test/process-args.js +++ b/test/process-args.js @@ -5,7 +5,7 @@ const yargs = require('yargs/yargs') const processArgs = require('../self-coverage/lib/process-args') -const nycBin = require.resolve('../bin/nyc.js') +const nycBin = require.resolve('../self-coverage/bin/nyc.js') test('hideInstrumenterArgs removes dashed options that proceed bin', async t => { process.argv = [