diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index 002b4aa0d..000000000
--- a/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "presets": ["env"]
-}
diff --git a/package-lock.json b/package-lock.json
index 0fbf2cc3d..1f32fa7ee 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -864,6 +864,31 @@
"safe-buffer": "^5.0.1"
}
},
+ "cross-env": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
+ "integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^6.0.5",
+ "is-windows": "^1.0.0"
+ },
+ "dependencies": {
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "dev": true,
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ }
+ }
+ },
"cross-spawn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
diff --git a/package.json b/package.json
index 372e2c28d..e0aa83eb7 100644
--- a/package.json
+++ b/package.json
@@ -4,12 +4,14 @@
"description": "the Istanbul command line interface",
"main": "index.js",
"scripts": {
- "pretest": "npm run clean && npm run instrument",
- "test": "tap -t360 --no-cov -b ./test/*.js && npm run report",
- "posttest": "standard",
+ "lint": "standard",
+ "pretest": "npm run lint && npm run clean && npm run instrument",
+ "test": "tap -t360 --no-cov -b test/*.js",
+ "snap": "cross-env TAP_SNAPSHOT=1 tap -t360 --no-cov -b test/*.js",
+ "posttest": "npm run report",
"clean": "rimraf ./.nyc_output ./node_modules/.cache ./.self_coverage ./test/fixtures/.nyc_output ./test/fixtures/node_modules/.cache ./self-coverage",
"instrument": "node ./build-self-coverage.js",
- "report": "node ./self-coverage/bin/nyc report --temp-dir ./.self_coverage/ -r text -r lcov",
+ "report": "node ./bin/nyc report --temp-dir ./.self_coverage/ -r text -r lcov",
"release": "standard-version"
},
"bin": {
@@ -96,9 +98,11 @@
"any-path": "^1.3.0",
"chai": "^4.2.0",
"coveralls": "^3.0.3",
+ "cross-env": "^5.2.0",
"is-windows": "^1.0.2",
"lodash": "^4.17.11",
"newline-regex": "^0.2.1",
+ "pify": "^4.0.1",
"requirejs": "^2.3.6",
"sanitize-filename": "^1.6.1",
"source-map-support": "^0.5.12",
diff --git a/tap-snapshots/test-nyc-integration.js-TAP.test.js b/tap-snapshots/test-nyc-integration.js-TAP.test.js
new file mode 100644
index 000000000..df52956a9
--- /dev/null
+++ b/tap-snapshots/test-nyc-integration.js-TAP.test.js
@@ -0,0 +1,566 @@
+/* IMPORTANT
+ * This snapshot file is auto-generated, but designed for humans.
+ * It should be checked into source control and tracked carefully.
+ * Re-generate by setting TAP_SNAPSHOT=1 and running tests.
+ * Make sure to inspect the output below. Do not ignore changes!
+ */
+'use strict'
+exports[`test/nyc-integration.js TAP --include can be used to limit bin to instrumenting specific files > stdout 1`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --exclude should allow default exclude rules to be overridden > stdout 1`] = `
+---------------------------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+---------------------------------|----------|----------|----------|----------|-------------------|
+All files | 0 | 0 | 0 | 0 | |
+ cli | 0 | 0 | 0 | 0 | |
+ args.js | 0 | 100 | 100 | 0 | 1 |
+ by-arg2.js | 0 | 0 | 100 | 0 | 1,2,3,4,5,7 |
+ classes.js | 0 | 100 | 0 | 0 | 5,6,11,15 |
+ empty.js | 0 | 0 | 0 | 0 | |
+ env.js | 0 | 100 | 100 | 0 | 1 |
+ es6.js | 0 | 100 | 0 | 0 |... 11,16,17,22,23 |
+ external-instrumenter.js | 0 | 0 | 0 | 0 | 1 |
+ gc.js | 0 | 100 | 100 | 0 | 2,3 |
+ half-covered-failing.js | 0 | 0 | 100 | 0 | 1,3,5,6,7,8 |
+ selfspawn-fibonacci.js | 0 | 0 | 0 | 0 |... 24,25,26,27,28 |
+ skip-full.js | 0 | 100 | 100 | 0 | 1,2 |
+ test.js | 0 | 0 | 0 | 0 | |
+ cli/fakebin | 0 | 100 | 100 | 0 | |
+ npm-template.js | 0 | 100 | 100 | 0 | 2,3,4,7,9 |
+ cli/nyc-config-js | 0 | 0 | 100 | 0 | |
+ ignore.js | 0 | 100 | 100 | 0 | 1 |
+ index.js | 0 | 0 | 100 | 0 | 1,3,5,7,8,9,10 |
+ nyc.config.js | 0 | 100 | 100 | 0 | 1 |
+ nycrc-config.js | 0 | 100 | 100 | 0 | 1 |
+ cli/nycrc | 0 | 0 | 100 | 0 | |
+ ignore.js | 0 | 100 | 100 | 0 | 1 |
+ index.js | 0 | 0 | 100 | 0 | 1,3,5,7,8,9,10 |
+ cli/subdir/input-dir | 0 | 100 | 100 | 0 | |
+ index.js | 0 | 100 | 100 | 0 | 2 |
+ cli/subdir/input-dir/exclude-me | 0 | 100 | 100 | 0 | |
+ index.js | 0 | 100 | 100 | 0 | 2 |
+ cli/subdir/input-dir/include-me | 0 | 100 | 100 | 0 | |
+ exclude-me.js | 0 | 100 | 100 | 0 | 2 |
+ include-me.js | 0 | 100 | 100 | 0 | 2 |
+---------------------------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP report and check should show coverage check along with report > stdout 1`] = `
+
+`
+
+exports[`test/nyc-integration.js TAP report and check should show coverage check along with report > stderr 1`] = `
+ERROR: Coverage for lines (50%) does not meet global threshold (100%)
+
+`
+
+exports[`test/nyc-integration.js TAP report and check should show coverage check along with report > stdout 2`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --ignore-class-method skips methods that match ignored name but still catches those that are not > stdout 1`] = `
+---------------------------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+---------------------------------|----------|----------|----------|----------|-------------------|
+All files | 1.61 | 0 | 5.56 | 2.15 | |
+ cli | 2.33 | 0 | 5.56 | 3.64 | |
+ args.js | 0 | 100 | 100 | 0 | 1 |
+ by-arg2.js | 0 | 0 | 100 | 0 | 1,2,3,4,5,7 |
+ classes.js | 66.67 | 100 | 50 | 66.67 | 6 |
+ empty.js | 0 | 0 | 0 | 0 | |
+ env.js | 0 | 100 | 100 | 0 | 1 |
+ es6.js | 0 | 100 | 0 | 0 |... 11,16,17,22,23 |
+ external-instrumenter.js | 0 | 0 | 0 | 0 | 1 |
+ gc.js | 0 | 100 | 100 | 0 | 2,3 |
+ half-covered-failing.js | 0 | 0 | 100 | 0 | 1,3,5,6,7,8 |
+ half-covered.js | 0 | 0 | 100 | 0 | 1,3,5,6,7,8 |
+ selfspawn-fibonacci.js | 0 | 0 | 0 | 0 |... 24,25,26,27,28 |
+ skip-full.js | 0 | 100 | 100 | 0 | 1,2 |
+ cli/fakebin | 0 | 100 | 100 | 0 | |
+ npm-template.js | 0 | 100 | 100 | 0 | 2,3,4,7,9 |
+ cli/nyc-config-js | 0 | 0 | 100 | 0 | |
+ ignore.js | 0 | 100 | 100 | 0 | 1 |
+ index.js | 0 | 0 | 100 | 0 | 1,3,5,7,8,9,10 |
+ nycrc-config.js | 0 | 100 | 100 | 0 | 1 |
+ cli/nycrc | 0 | 0 | 100 | 0 | |
+ ignore.js | 0 | 100 | 100 | 0 | 1 |
+ index.js | 0 | 0 | 100 | 0 | 1,3,5,7,8,9,10 |
+ cli/run-npm-test | 0 | 0 | 100 | 0 | |
+ half-covered.js | 0 | 0 | 100 | 0 | 1,3,5,6,7,8 |
+ cli/run-npm-test-recursive | 0 | 0 | 100 | 0 | |
+ half-covered.js | 0 | 0 | 100 | 0 | 1,3,5,6,7,8 |
+ cli/subdir/input-dir | 0 | 100 | 100 | 0 | |
+ index.js | 0 | 100 | 100 | 0 | 2 |
+ cli/subdir/input-dir/exclude-me | 0 | 100 | 100 | 0 | |
+ index.js | 0 | 100 | 100 | 0 | 2 |
+ cli/subdir/input-dir/include-me | 0 | 100 | 100 | 0 | |
+ exclude-me.js | 0 | 100 | 100 | 0 | 2 |
+ include-me.js | 0 | 100 | 100 | 0 | 2 |
+---------------------------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when the expected coverage is below a threshold > stderr 1`] = `
+ERROR: Coverage for lines (50%) does not meet global threshold (51%)
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when the expected coverage is below a threshold > stdout 1`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when check-coverage command is used rather than flag > stdout 1`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when check-coverage command is used rather than flag > stderr 1`] = `
+ERROR: Coverage for lines (50%) does not meet global threshold (51%)
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when check-coverage command is used rather than flag > stdout 2`] = `
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage succeeds when the expected coverage is above a threshold > stdout 1`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails in any case when the underlying test failed > stderr 1`] = `
+ERROR: Coverage for lines (33.33%) does not meet global threshold (49%)
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails in any case when the underlying test failed > stdout 1`] = `
+-------------------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-------------------------|----------|----------|----------|----------|-------------------|
+All files | 33.33 | 0 | 100 | 33.33 | |
+ half-covered-failing.js | 33.33 | 0 | 100 | 33.33 | 5,6,7,8 |
+-------------------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when the expected file coverage is below a threshold > stderr 1`] = `
+ERROR: Coverage for lines (50%) does not meet threshold (51%) for ./half-covered.js
+
+`
+
+exports[`test/nyc-integration.js TAP --check-coverage fails when the expected file coverage is below a threshold > stdout 1`] = `
+-----------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+-----------------|----------|----------|----------|----------|-------------------|
+All files | 50 | 50 | 100 | 50 | |
+ half-covered.js | 50 | 50 | 100 | 50 | 6,7,8 |
+-----------------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP passes configuration via environment variables > undefined 1`] = `
+{ silent: true,
+ cache: false,
+ sourceMap: true,
+ require: 'make-dir',
+ include: 'env.js',
+ exclude: 'batman.js',
+ extension: '.js',
+ cacheDir: '/tmp',
+ instrumenter: './lib/instrumenters/istanbul' }
+`
+
+exports[`test/nyc-integration.js TAP allows package.json configuration to be overridden with command line args > stdout 1`] = `
+TN:
+SF:./half-covered.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:6,0
+DA:7,0
+DA:8,0
+LF:6
+LH:3
+BRDA:5,0,0,0
+BRDA:5,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from package.json and nyc.config.js > stdout 1`] = `
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from different module rather than nyc.config.js > stderr 1`] = `
+ERROR: Coverage for lines (57.14%) does not meet threshold (100%) for ./index.js
+ERROR: Coverage for branches (50%) does not meet threshold (100%) for ./index.js
+ERROR: Coverage for statements (57.14%) does not meet threshold (100%) for ./index.js
+ERROR: Coverage for lines (0%) does not meet threshold (100%) for ./nyc.config.js
+ERROR: Coverage for statements (0%) does not meet threshold (100%) for ./nyc.config.js
+ERROR: Coverage for lines (0%) does not meet threshold (100%) for ./nycrc-config.js
+ERROR: Coverage for statements (0%) does not meet threshold (100%) for ./nycrc-config.js
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from different module rather than nyc.config.js > stdout 1`] = `
+TN:
+SF:./ignore.js
+FNF:0
+FNH:0
+DA:1,1
+LF:1
+LH:1
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+TN:
+SF:./nyc.config.js
+FNF:0
+FNH:0
+DA:1,0
+LF:1
+LH:0
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./nycrc-config.js
+FNF:0
+FNH:0
+DA:1,0
+LF:1
+LH:0
+BRF:0
+BRH:0
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP allows nyc.config.js configuration to be overridden with command line args > stdout 1`] = `
+TN:
+SF:./ignore.js
+FNF:0
+FNH:0
+DA:1,1
+LF:1
+LH:1
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+TN:
+SF:./nyc.config.js
+FNF:0
+FNH:0
+DA:1,0
+LF:1
+LH:0
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./nycrc-config.js
+FNF:0
+FNH:0
+DA:1,0
+LF:1
+LH:0
+BRF:0
+BRH:0
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from package.json and .nycrc > stdout 1`] = `
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from different file rather than .nycrc > stderr 1`] = `
+ERROR: Coverage for lines (57.14%) does not meet threshold (100%) for ./index.js
+ERROR: Coverage for branches (50%) does not meet threshold (100%) for ./index.js
+ERROR: Coverage for statements (57.14%) does not meet threshold (100%) for ./index.js
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from different file rather than .nycrc > stdout 1`] = `
+TN:
+SF:./ignore.js
+FNF:0
+FNH:0
+DA:1,1
+LF:1
+LH:1
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from .nycrc.yml > stdout 1`] = `
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP loads configuration from .nycrc.yaml > stdout 1`] = `
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP allows .nycrc configuration to be overridden with command line args > stdout 1`] = `
+TN:
+SF:./ignore.js
+FNF:0
+FNH:0
+DA:1,1
+LF:1
+LH:1
+BRF:0
+BRH:0
+end_of_record
+TN:
+SF:./index.js
+FNF:0
+FNH:0
+DA:1,1
+DA:3,1
+DA:5,1
+DA:7,1
+DA:8,0
+DA:9,0
+DA:10,0
+LF:7
+LH:4
+BRDA:7,0,0,0
+BRDA:7,0,1,1
+BRF:2
+BRH:1
+end_of_record
+
+`
+
+exports[`test/nyc-integration.js TAP reports appropriate coverage information for es6 source files > stdout 1`] = `
+sup
+do not hit
+----------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+----------|----------|----------|----------|----------|-------------------|
+All files | 62.5 | 100 | 40 | 62.5 | |
+ es6.js | 62.5 | 100 | 40 | 62.5 | 11,16,17 |
+----------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP hooks provide coverage for requireJS and AMD modules > stdout 1`] = `
+----------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+----------|----------|----------|----------|----------|-------------------|
+All files | 100 | 100 | 100 | 100 | |
+ ipsum.js | 100 | 100 | 100 | 100 | |
+ lorem.js | 100 | 100 | 100 | 100 | |
+----------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP does not interpret args intended for instrumented bin > undefined 1`] = `
+[ '--help', '--version' ]
+`
+
+exports[`test/nyc-integration.js TAP interprets first args after -- as Node.js execArgv > stdout 1`] = `
+I’m still running
+----------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+----------|----------|----------|----------|----------|-------------------|
+All files | 100 | 100 | 100 | 100 | |
+ gc.js | 100 | 100 | 100 | 100 | |
+----------|----------|----------|----------|----------|-------------------|
+
+`
+
+exports[`test/nyc-integration.js TAP --show-process-tree displays a tree of spawned processes > stdout 1`] = `
+3
+------------------------|----------|----------|----------|----------|-------------------|
+File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
+------------------------|----------|----------|----------|----------|-------------------|
+All files | 90.91 | 70 | 100 | 100 | |
+ selfspawn-fibonacci.js | 90.91 | 70 | 100 | 100 | 4,25,27 |
+------------------------|----------|----------|----------|----------|-------------------|
+nyc
+└─┬ node ./selfspawn-fibonacci.js 5
+ │ 100 % Lines
+ ├─┬ node ./selfspawn-fibonacci.js 4
+ │ │ 100 % Lines
+ │ ├─┬ node ./selfspawn-fibonacci.js 3
+ │ │ │ 100 % Lines
+ │ │ ├── node ./selfspawn-fibonacci.js 2
+ │ │ │ 31.58 % Lines
+ │ │ └── node ./selfspawn-fibonacci.js 1
+ │ │ 26.32 % Lines
+ │ └── node ./selfspawn-fibonacci.js 2
+ │ 31.58 % Lines
+ └─┬ node ./selfspawn-fibonacci.js 3
+ │ 100 % Lines
+ ├── node ./selfspawn-fibonacci.js 2
+ │ 31.58 % Lines
+ └── node ./selfspawn-fibonacci.js 1
+ 26.32 % Lines
+
+
+`
diff --git a/test/fixtures/cli/half-covered-failing.js b/test/fixtures/cli/half-covered-failing.js
index 254a54f0b..026512b64 100644
--- a/test/fixtures/cli/half-covered-failing.js
+++ b/test/fixtures/cli/half-covered-failing.js
@@ -1,6 +1,6 @@
var a = 0
-throw new Error
+process.exit(1)
if (a === 0) {
a++;
diff --git a/test/helpers/index.js b/test/helpers/index.js
new file mode 100644
index 000000000..78297caf8
--- /dev/null
+++ b/test/helpers/index.js
@@ -0,0 +1,12 @@
+'use strict'
+
+const { fixturesCLI, nycBin } = require('./paths')
+
+module.exports = {
+ fixturesCLI,
+ nycBin,
+ testSuccess: require('./test-success'),
+ testFailure: require('./test-failure'),
+ runNYC: require('./run-nyc'),
+ tempDirSetup: require('./temp-dir-setup')
+}
diff --git a/test/helpers/paths.js b/test/helpers/paths.js
new file mode 100644
index 000000000..0bca0156a
--- /dev/null
+++ b/test/helpers/paths.js
@@ -0,0 +1,8 @@
+'use strict'
+
+const path = require('path')
+
+module.exports = {
+ nycBin: require.resolve('../../self-coverage/bin/nyc'),
+ fixturesCLI: path.resolve(__dirname, '../fixtures/cli')
+}
diff --git a/test/helpers/run-nyc.js b/test/helpers/run-nyc.js
new file mode 100644
index 000000000..c8ac93d1d
--- /dev/null
+++ b/test/helpers/run-nyc.js
@@ -0,0 +1,40 @@
+'use strict'
+
+const { nycBin, fixturesCLI } = require('./paths')
+const spawn = require('./spawn')
+
+const env = {
+ PATH: process.env.PATH
+}
+
+function sanitizeString (str, cwd, leavePathSep) {
+ /*
+ * File paths are different on different systems:
+ * - make everything relative to cwd
+ * - replace full node path with 'node'
+ * - replace all Windows path separators ('\\') with POSIX path separators
+ */
+ str = str
+ .split(cwd).join('.')
+ .split(process.execPath).join('node')
+
+ if (!leavePathSep) {
+ str = str.replace(/\\/g, '/')
+ }
+
+ return str
+}
+
+function runNYC ({ args, tempDir, leavePathSep, cwd = fixturesCLI }) {
+ const runArgs = [nycBin].concat(tempDir ? ['--temp-dir', tempDir] : [], args)
+ return spawn(process.execPath, runArgs, {
+ cwd: cwd,
+ env
+ }).then(({ status, stderr, stdout }) => ({
+ status,
+ stderr: sanitizeString(stderr, cwd, leavePathSep),
+ stdout: sanitizeString(stdout, cwd, leavePathSep)
+ }))
+}
+
+module.exports = runNYC
diff --git a/test/helpers/spawn.js b/test/helpers/spawn.js
new file mode 100644
index 000000000..c8aae3029
--- /dev/null
+++ b/test/helpers/spawn.js
@@ -0,0 +1,23 @@
+const cp = require('child_process')
+
+function spawn (exe, args, opts) {
+ return new Promise((resolve, reject) => {
+ const proc = cp.spawn(exe, args, opts)
+ const stdout = []
+ const stderr = []
+
+ proc.stdout.on('data', buf => stdout.push(buf))
+ proc.stderr.on('data', buf => stderr.push(buf))
+
+ proc.on('error', reject)
+ proc.on('close', status => {
+ resolve({
+ status,
+ stdout: Buffer.concat(stdout).toString(),
+ stderr: Buffer.concat(stderr).toString()
+ })
+ })
+ })
+}
+
+module.exports = spawn
diff --git a/test/helpers/temp-dir-setup.js b/test/helpers/temp-dir-setup.js
new file mode 100644
index 000000000..bb9beceb1
--- /dev/null
+++ b/test/helpers/temp-dir-setup.js
@@ -0,0 +1,33 @@
+'use strict'
+
+const path = require('path')
+const fs = require('fs')
+const makeDir = require('make-dir')
+const _rimraf = require('rimraf')
+const pify = require('pify')
+
+const rimraf = pify(_rimraf)
+const mkdtemp = pify(fs.mkdtemp)
+
+function tempDirSetup (t, testFile) {
+ const { dir, name } = path.parse(testFile)
+ const tempDirBase = path.resolve(dir, 'temp-dir-' + name)
+
+ makeDir.sync(tempDirBase)
+
+ // Do not use arrow function for beforeEach
+ // or afterEach, they need this from tap.
+ t.beforeEach(function () {
+ return mkdtemp(tempDirBase + '/').then(tempDir => {
+ this.tempDir = tempDir
+ })
+ })
+
+ t.afterEach(function () {
+ return rimraf(this.tempDir)
+ })
+
+ t.tearDown(() => rimraf(tempDirBase))
+}
+
+module.exports = tempDirSetup
diff --git a/test/helpers/test-failure.js b/test/helpers/test-failure.js
new file mode 100644
index 000000000..7d891d24c
--- /dev/null
+++ b/test/helpers/test-failure.js
@@ -0,0 +1,14 @@
+'use strict'
+
+const runNYC = require('./run-nyc')
+
+function testFailure (t, opts) {
+ opts.tempDir = t.tempDir
+ return runNYC(opts).then(({ status, stderr, stdout }) => {
+ t.equal(status, 1)
+ t.matchSnapshot(stderr, 'stderr')
+ t.matchSnapshot(stdout, 'stdout')
+ })
+}
+
+module.exports = testFailure
diff --git a/test/helpers/test-success.js b/test/helpers/test-success.js
new file mode 100644
index 000000000..90abbf724
--- /dev/null
+++ b/test/helpers/test-success.js
@@ -0,0 +1,14 @@
+'use strict'
+
+const runNYC = require('./run-nyc')
+
+function testSuccess (t, opts) {
+ opts.tempDir = t.tempDir
+ return runNYC(opts).then(({ status, stderr, stdout }) => {
+ t.equal(status, 0)
+ t.equal(stderr, '')
+ t.matchSnapshot(stdout, 'stdout')
+ })
+}
+
+module.exports = testSuccess
diff --git a/test/nyc-integration-old.js b/test/nyc-integration-old.js
new file mode 100644
index 000000000..ca7c28a43
--- /dev/null
+++ b/test/nyc-integration-old.js
@@ -0,0 +1,1402 @@
+/* global describe, it, beforeEach, afterEach */
+
+// TODO: finish migrating these tests to use snapshots
+const _ = require('lodash')
+const path = require('path')
+const bin = path.resolve(__dirname, '../self-coverage/bin/nyc')
+const fixturesCLI = path.resolve(__dirname, './fixtures/cli')
+const fixturesSourceMaps = path.resolve(__dirname, './fixtures/source-maps')
+const fakebin = path.resolve(fixturesCLI, 'fakebin')
+const fs = require('fs')
+const glob = require('glob')
+const isWindows = require('is-windows')()
+const rimraf = require('rimraf')
+const makeDir = require('make-dir')
+const { spawn, spawnSync } = require('child_process')
+const si = require('strip-indent')
+
+require('chai').should()
+require('tap').mochaGlobals()
+
+// beforeEach
+rimraf.sync(path.resolve(fakebin, 'node'))
+rimraf.sync(path.resolve(fakebin, 'npm'))
+rimraf.sync(path.resolve(fixturesCLI, 'subdir', 'output-dir'))
+
+describe('the nyc cli', function () {
+ var env = { PATH: process.env.PATH }
+
+ // https://github.com/bcoe/nyc/issues/190
+ describe('running "npm test"', function () {
+ it('can run "npm test" which directly invokes a test file', function (done) {
+ var args = [bin, 'npm', 'test']
+ var directory = path.resolve(fixturesCLI, 'run-npm-test')
+ var proc = spawn(process.execPath, args, {
+ cwd: directory,
+ env: env
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ done()
+ })
+ })
+
+ it('can run "npm test" which indirectly invokes a test file', function (done) {
+ var args = [bin, 'npm', 'test']
+ var directory = path.resolve(fixturesCLI, 'run-npm-test-recursive')
+ var proc = spawn(process.execPath, args, {
+ cwd: directory,
+ env: env
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ done()
+ })
+ })
+
+ function writeFakeNPM (shebang) {
+ var targetPath = path.resolve(fakebin, 'npm')
+ var source = fs.readFileSync(path.resolve(fakebin, 'npm-template.js'))
+ fs.writeFileSync(targetPath, '#!' + shebang + '\n' + source)
+ fs.chmodSync(targetPath, 493) // 0o755
+ }
+
+ it('can run "npm test", absolute shebang edition', function (done) {
+ if (isWindows) return done()
+
+ writeFakeNPM(process.execPath)
+
+ var args = [bin, 'npm', 'test']
+ var directory = path.resolve(fixturesCLI, 'run-npm-test-recursive')
+ var proc = spawn(process.execPath, args, {
+ cwd: directory,
+ env: {
+ PATH: fakebin + ':' + env.PATH
+ }
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ done()
+ })
+ })
+
+ it('can run "npm test", weird bash+dirname shebang edition', function (done) {
+ if (isWindows) return done()
+
+ // This string is taken verbatim from tools/install.py in Node core v5.x
+ writeFakeNPM('/bin/sh\n// 2>/dev/null; exec "`dirname "$0"`/node" "$0" "$@"')
+ fs.symlinkSync(process.execPath, path.resolve(fakebin, 'node'))
+
+ var args = [bin, 'npm', 'test']
+ var directory = path.resolve(fixturesCLI, 'run-npm-test-recursive')
+ var proc = spawn(process.execPath, args, {
+ cwd: directory,
+ env: {
+ PATH: fakebin + ':' + env.PATH
+ }
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ done()
+ })
+ })
+ })
+
+ describe('instrument', function () {
+ beforeEach(() => {
+ rimraf.sync(path.resolve(fixturesCLI, 'subdir', 'output-dir'))
+ })
+
+ describe('no output folder', function () {
+ it('allows a single file to be instrumented', function (done) {
+ var args = [bin, 'instrument', './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.contain(`path:${JSON.stringify(path.resolve(fixturesCLI, 'half-covered.js'))}`)
+ done()
+ })
+ })
+
+ it('allows a directory of files to be instrumented', function (done) {
+ var args = [bin, 'instrument', './']
+
+ 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(/half-covered\.js"/)
+ stdout.should.match(/half-covered-failing\.js"/)
+ stdout.should.not.match(/spawn\.js"/)
+ done()
+ })
+ })
+
+ it('returns unmodified source if there is no transform', function (done) {
+ const args = [bin, 'instrument', './no-transform/half-covered.xjs']
+
+ const proc = spawn(process.execPath, args, {
+ cwd: fixturesCLI,
+ env: env
+ })
+
+ let stdout = ''
+ proc.stdout.on('data', function (chunk) {
+ stdout += chunk
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ stdout.should.contain(`var a = 0`)
+ done()
+ })
+ })
+ })
+
+ describe('output folder specified', function () {
+ afterEach(function () {
+ rimraf.sync(path.resolve(fixturesCLI, 'output'))
+ })
+
+ it('works in directories without a package.json', function (done) {
+ const args = [bin, 'instrument', './input-dir', './output-dir']
+
+ const subdir = path.resolve(fixturesCLI, 'subdir')
+ const proc = spawn(process.execPath, args, {
+ cwd: subdir,
+ env: env
+ })
+
+ proc.on('exit', function (code) {
+ code.should.equal(0)
+ const target = path.resolve(subdir, 'output-dir', 'index.js')
+ fs.readFileSync(target, 'utf8')
+ .should.match(/console.log\('Hello, World!'\)/)
+ done()
+ })
+ })
+
+ it('can be configured to exit on error', function (done) {
+ const args = [bin, 'instrument', '--exit-on-error', './input-dir', './output-dir']
+
+ const subdir = path.resolve(fixturesCLI, 'subdir')
+ const proc = spawn(process.execPath, args, {
+ cwd: subdir,
+ env: env
+ })
+
+ proc.on('exit', function (code) {
+ code.should.equal(1)
+ done()
+ })
+ })
+
+ it('allows a single file to be instrumented', function (done) {
+ const args = [bin, 'instrument', './half-covered.js', './output']
+
+ const inputPath = path.resolve(fixturesCLI, './half-covered.js')
+ const inputMode = fs.statSync(inputPath).mode & 0o7777
+ const newMode = 0o775
+ if (process.platform !== 'win32') {
+ fs.chmodSync(inputPath, newMode)
+ }
+
+ const proc = spawn(process.execPath, args, {
+ cwd: fixturesCLI,
+ env: env
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
+ files.length.should.equal(1)
+ files.should.include('half-covered.js')
+
+ if (process.platform !== 'win32') {
+ const outputPath = path.resolve(fixturesCLI, 'output', 'half-covered.js')
+ const outputMode = fs.statSync(outputPath).mode & 0o7777
+ outputMode.should.equal(newMode)
+
+ fs.chmodSync(inputPath, inputMode)
+ }
+
+ done()
+ })
+ })
+
+ it('allows a directory of files to be instrumented', function (done) {
+ const args = [bin, 'instrument', './nyc-config-js', './output']
+
+ const proc = spawn(process.execPath, args, {
+ cwd: fixturesCLI,
+ env: env
+ })
+
+ proc.on('close', function (code) {
+ code.should.equal(0)
+ const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
+ files.should.include('index.js')
+ files.should.include('ignore.js')
+ files.should.not.include('package.json')
+ files.should.not.include('node_modules')
+ const includeTarget = path.resolve(fixturesCLI, 'output', 'ignore.js')
+ fs.readFileSync(includeTarget, 'utf8')
+ .should.match(/var cov_/)
+ done()
+ })
+ })
+
+ it('copies all files from to