Repository: istanbuljs/nyc
Pull request #1082 (2019-04-22 12:28:39)

fix: Use correct config property for parser plugins


Patch:
diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index 002b4aa..0000000
--- a/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "presets": ["env"]
-}
diff --git a/README.md b/README.md
index d003242..cd3fc5b 100644
--- a/README.md
+++ b/README.md
@@ -195,24 +195,7 @@ Install custom reporters as a development dependency and you can use the `--repo
 nyc report --reporter=<custom-reporter-name>
 ```
 
-## Producing instrumented source
-
-The `nyc instrument` command can produce a set of instrumented source files.
-These files are suitable for client side deployment in end to end testing.
-You can create an instrumented version of your source code by running:
-
-```bash
-nyc instrument <input> [output]
-```
-
-`<input>` can be any file or directory within the project root directory.
-The `[output]` directory is optional and can be located anywhere, if it is not set the instrumented code will be sent to `stdout`.
-For example, `nyc instrument . ./output` will produce instrumented versions of any source files it finds in `.` and store them in `./output`.
-
-Any existing output can be removed by specifying the `--delete` option.
-Run `nyc instrument --help` to display a full list of available command options.
-
-**Note:** `nyc instrument` will not copy the contents of a `.git` folder to the output directory.
+## [Producing instrumented source](./docs/instrument.md)
 
 ## Setting the project root directory
 
diff --git a/docs/instrument.md b/docs/instrument.md
new file mode 100644
index 0000000..af19b6d
--- /dev/null
+++ b/docs/instrument.md
@@ -0,0 +1,41 @@
+# Producing instrumented source
+
+The `nyc instrument` command can produce instrumented source files.
+These files are suitable for client side deployment during end to end testing.
+You can either pre-instrument your source, or write instrumented source to a stream.
+
+Run `nyc instrument --help` to display a full list of available command options.
+ 
+## Pre-instrumented source 
+ 
+You can create pre-instrumented source code by running:
+
+```bash
+nyc instrument <input> [output]
+```
+
+`<input>` can be any file or directory within the project root directory.
+The `[output]` directory is optional and can be located anywhere, if not set the instrumented code will be sent to `stdout`.
+For example, `nyc instrument . ./output` will produce instrumented versions of any source files it finds in `.` and store them in `./output`.
+
+The `--delete` option will remove the existing output directory before instrumenting.
+
+The `--complete-copy` option will copy all remaining files from the `input` directory to the `output` directory.
+When using `--complete-copy` nyc will not copy the contents of a `.git` folder to the output directory.
+
+**Note:** `--complete-copy` will dereference any symlinks during the copy process, this may stop scripts running properly from the output directory.
+
+## Streaming instrumentation
+
+`nyc instrument` will stream instrumented source directly to `stdout`, that can then be piped to another process.
+You can use this behaviour to create a server that can instrument files on request.
+The following example shows streaming instrumentation middleware capable of instrumenting files on request.
+
+```javascript
+app.use((req, res, next) => {
+  const myOptions = ""
+  const filename = myHelper.getFilename(req)
+  const nyc = cp.spawn(`nyc instrument ${myOptions} ${filename}`)
+  nyc.stdout.pipe(res)
+})
+```
diff --git a/lib/instrumenters/istanbul.js b/lib/instrumenters/istanbul.js
index 4340f60..fa95e36 100644
--- a/lib/instrumenters/istanbul.js
+++ b/lib/instrumenters/istanbul.js
@@ -5,7 +5,7 @@ const convertSourceMap = require('convert-source-map')
 const mergeSourceMap = require('merge-source-map')
 
 function InstrumenterIstanbul (options) {
-  const plugins = options.parserPlugins
+  const { plugins } = options
   const configPlugins = plugins ? { plugins } : {}
 
   const instrumenter = createInstrumenter(Object.assign({
diff --git a/package-lock.json b/package-lock.json
index 0fbf2cc..1f32fa7 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 372e2c2..e0aa83e 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",


Test patch:
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 0000000..df52956
--- /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 254a54f..026512b 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 0000000..78297ca
--- /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 0000000..0bca015
--- /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 0000000..c8ac93d
--- /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 0000000..c8aae30
--- /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 0000000..bb9bece
--- /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 0000000..7d891d2
--- /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 0000000..90abbf7
--- /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 0000000..ca7c28a
--- /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 <input> to <output> as well as those that have been instrumented', function (done) {
+        const args = [bin, 'instrument', '--complete-copy', './nyc-config-js', './output']
+
+        // force node_modules to exist so we can verify that it is copied.
+        const nmDir = path.resolve(fixturesCLI, 'nyc-config-js', 'node_modules')
+        makeDir.sync(nmDir)
+        fs.writeFileSync(path.join(nmDir, 'test-file'), '')
+        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.include('package.json')
+          files.should.include('node_modules')
+          const includeTarget = path.resolve(fixturesCLI, 'output', 'ignore.js')
+          fs.readFileSync(includeTarget, 'utf8')
+            .should.match(/var cov_/)
+          done()
+        })
+      })
+
+      it('can instrument the project directory', function (done) {
+        const args = [bin, 'instrument', '.', './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('args.js')
+          files.should.include('subdir')
+          done()
+        })
+      })
+
+      it('allows a sub-directory of files to be instrumented', function (done) {
+        const args = [bin, 'instrument', './subdir/input-dir', './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')
+          done()
+        })
+      })
+
+      it('allows a subdirectory to be excluded via .nycrc file', function (done) {
+        const args = [bin, 'instrument', '--nycrc-path', './.instrument-nycrc', './subdir/input-dir', './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.length.should.not.equal(0)
+          files.should.include('exclude-me')
+          files.should.include('node_modules')
+          files.should.include('index.js')
+          files.should.include('bad.js')
+          const includeTarget = path.resolve(fixturesCLI, 'output', 'index.js')
+          fs.readFileSync(includeTarget, 'utf8')
+            .should.match(/var cov_/)
+          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
+          fs.readFileSync(excludeTarget, 'utf8')
+            .should.not.match(/var cov_/)
+          done()
+        })
+      })
+
+      it('allows a file to be excluded', function (done) {
+        const args = [bin, 'instrument', '--complete-copy', '--exclude', 'exclude-me/index.js', './subdir/input-dir', './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.length.should.not.equal(0)
+          files.should.include('exclude-me')
+          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
+          fs.readFileSync(excludeTarget, 'utf8')
+            .should.not.match(/var cov_/)
+          done()
+        })
+      })
+
+      it('allows specifying a single sub-directory to be included', function (done) {
+        const args = [bin, 'instrument', '--include', '**/include-me/**', './subdir/input-dir', './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.length.should.not.equal(0)
+          files.should.include('include-me')
+          const instrumented = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
+          fs.readFileSync(instrumented, 'utf8')
+            .should.match(/var cov_/)
+          done()
+        })
+      })
+
+      it('allows a file to be excluded from an included directory', function (done) {
+        const args = [bin, 'instrument', '--complete-copy', '--exclude', '**/exclude-me.js', '--include', '**/include-me/**', './subdir/input-dir', './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.length.should.not.equal(0)
+          files.should.include('include-me')
+          const includeMeFiles = fs.readdirSync(path.resolve(fixturesCLI, 'output', 'include-me'))
+          includeMeFiles.length.should.not.equal(0)
+          includeMeFiles.should.include('include-me.js')
+          includeMeFiles.should.include('exclude-me.js')
+          const includeTarget = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
+          fs.readFileSync(includeTarget, 'utf8')
+            .should.match(/var cov_/)
+          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
+          fs.readFileSync(excludeTarget, 'utf8')
+            .should.not.match(/var cov_/)
+          done()
+        })
+      })
+
+      it('aborts if trying to write files in place', function (done) {
+        const args = [bin, 'instrument', '--delete', './', './']
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesCLI,
+          env: env
+        })
+
+        let stderr = ''
+        proc.stderr.on('data', function (chunk) {
+          stderr += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(1)
+          stderr.should.include('nyc instrument failed: cannot instrument files in place')
+          done()
+        })
+      })
+
+      it('aborts if trying to instrument files from outside the project root directory', function (done) {
+        const args = [bin, 'instrument', '--delete', '../', './']
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesCLI,
+          env: env
+        })
+
+        let stderr = ''
+        proc.stderr.on('data', function (chunk) {
+          stderr += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(1)
+          stderr.should.include('nyc instrument failed: cannot instrument files outside of project root directory')
+          done()
+        })
+      })
+
+      describe('es-modules', function () {
+        afterEach(function () {
+          rimraf.sync(path.resolve(fixturesCLI, './output'))
+        })
+
+        it('instruments file with `package` keyword when es-modules is disabled', function (done) {
+          const args = [bin, 'instrument', '--no-es-modules', './not-strict.js', './output']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(0)
+            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
+            subdirExists.should.equal(true)
+            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
+            files.should.include('not-strict.js')
+            done()
+          })
+        })
+
+        it('fails on file with `package` keyword when es-modules is enabled', function (done) {
+          const args = [bin, 'instrument', '--exit-on-error', './not-strict.js', './output']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          let stderr = ''
+          proc.stderr.on('data', function (chunk) {
+            stderr += chunk
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(1)
+            stdoutShouldEqual(stderr, `
+              Failed to instrument ${path.resolve(fixturesCLI, 'not-strict.js')}`)
+            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
+            subdirExists.should.equal(false)
+            done()
+          })
+        })
+      })
+
+      describe('delete', function () {
+        beforeEach(function () {
+          makeDir.sync(path.resolve(fixturesCLI, 'output', 'removed-by-clean'))
+        })
+
+        it('cleans the output directory if `--delete` is specified', function (done) {
+          const args = [bin, 'instrument', '--delete', 'true', './subdir/input-dir', './output']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(0)
+            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
+            subdirExists.should.equal(true)
+            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
+            files.should.not.include('removed-by-clean')
+            files.should.include('exclude-me')
+            done()
+          })
+        })
+
+        it('does not clean the output directory by default', function (done) {
+          const args = [bin, 'instrument', './subdir/input-dir', './output']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(0)
+            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
+            subdirExists.should.equal(true)
+            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
+            files.should.include('removed-by-clean')
+            done()
+          })
+        })
+
+        it('aborts if trying to clean process.cwd()', function (done) {
+          const args = [bin, 'instrument', '--delete', './src', './']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          let stderr = ''
+          proc.stderr.on('data', function (chunk) {
+            stderr += chunk
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(1)
+            stderr.should.include('nyc instrument failed: attempt to delete')
+            done()
+          })
+        })
+
+        it('aborts if trying to clean outside working directory', function (done) {
+          const args = [bin, 'instrument', '--delete', './', '../']
+
+          const proc = spawn(process.execPath, args, {
+            cwd: fixturesCLI,
+            env: env
+          })
+
+          let stderr = ''
+          proc.stderr.on('data', function (chunk) {
+            stderr += chunk
+          })
+
+          proc.on('close', function (code) {
+            code.should.equal(1)
+            stderr.should.include('nyc instrument failed: attempt to delete')
+            done()
+          })
+        })
+      })
+    })
+  })
+
+  it('help shows to stderr when main command doesn\'t know what to do', () => {
+    const opts = {
+      cwd: fixturesCLI,
+      env,
+      encoding: 'utf8'
+    }
+
+    const help = spawnSync(process.execPath, [bin, '--help'], opts)
+    const unknown = spawnSync(process.execPath, [bin], opts)
+    help.status.should.equal(0)
+    unknown.status.should.equal(1)
+    help.stderr.should.equal('')
+    unknown.stdout.should.equal('')
+    help.stdout.should.not.equal('')
+    help.stdout.should.equal(unknown.stderr)
+  })
+
+  describe('--temp-dir', function () {
+    beforeEach(() => {
+      rimraf.sync(path.resolve(fixturesCLI, '.nyc_output'))
+      rimraf.sync(path.resolve(fixturesCLI, '.temp_directory'))
+      rimraf.sync(path.resolve(fixturesCLI, '.temp_dir'))
+    })
+
+    it('creates the default \'tempDir\' when none is specified', function (done) {
+      var args = [bin, process.execPath, './half-covered.js']
+
+      var proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      proc.on('close', function (code) {
+        code.should.equal(0)
+        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.nyc_output'))
+        tempFiles.length.should.equal(2) // the coverage file, and processinfo
+        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
+        cliFiles.should.include('.nyc_output')
+        cliFiles.should.not.include('.temp_dir')
+        cliFiles.should.not.include('.temp_directory')
+        done()
+      })
+    })
+
+    it('prefers \'tempDirectory\' to \'tempDir\'', function (done) {
+      var args = [bin, '--tempDirectory', '.temp_directory', '--tempDir', '.temp_dir', process.execPath, './half-covered.js']
+
+      var proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      proc.on('exit', function (code) {
+        code.should.equal(0)
+        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.temp_directory'))
+        tempFiles.length.should.equal(2)
+        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
+        cliFiles.should.not.include('.nyc_output')
+        cliFiles.should.not.include('.temp_dir')
+        cliFiles.should.include('.temp_directory')
+        done()
+      })
+    })
+
+    it('uses the \'tempDir\' option if \'tempDirectory\' is not set', function (done) {
+      var args = [bin, '--tempDir', '.temp_dir', process.execPath, './half-covered.js']
+
+      var proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      proc.on('exit', function (code) {
+        code.should.equal(0)
+        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.temp_dir'))
+        tempFiles.length.should.equal(2)
+        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
+        cliFiles.should.not.include('.nyc_output')
+        cliFiles.should.include('.temp_dir')
+        cliFiles.should.not.include('.temp_directory')
+        rimraf.sync(path.resolve(fixturesCLI, '.temp_dir'))
+        done()
+      })
+    })
+  })
+
+  it('handles --clean / --no-clean properly', () => {
+    rimraf.sync(path.resolve(fixturesCLI, '.nyc_output'))
+    const args = (doClean, arg) => [
+      bin,
+      doClean ? '--clean' : '--no-clean',
+      process.execPath,
+      './by-arg2.js',
+      arg
+    ]
+    const opts = {
+      cwd: fixturesCLI,
+      env: env,
+      encoding: 'utf8'
+    }
+
+    const proc1 = spawnSync(process.execPath, args(true, '1'), opts)
+    proc1.status.should.equal(0)
+    stdoutShouldEqual(proc1.stdout, `
+      1
+      ------------|----------|----------|----------|----------|-------------------|
+      File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+      ------------|----------|----------|----------|----------|-------------------|
+      All files   |       50 |       25 |      100 |       50 |                   |
+       by-arg2.js |       50 |       25 |      100 |       50 |             4,5,7 |
+      ------------|----------|----------|----------|----------|-------------------|`
+    )
+    proc1.stderr.should.equal('')
+
+    const proc2 = spawnSync(process.execPath, args(false, '2'), opts)
+    proc2.status.should.equal(0)
+    stdoutShouldEqual(proc2.stdout, `
+      2
+      ------------|----------|----------|----------|----------|-------------------|
+      File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+      ------------|----------|----------|----------|----------|-------------------|
+      All files   |    83.33 |       75 |      100 |    83.33 |                   |
+       by-arg2.js |    83.33 |       75 |      100 |    83.33 |                 7 |
+      ------------|----------|----------|----------|----------|-------------------|`
+    )
+    proc2.stderr.should.equal('')
+  })
+
+  describe('noop instrumenter', function () {
+    it('setting instrument to "false" configures noop instrumenter', function (done) {
+      var args = [
+        bin,
+        '--silent',
+        '--no-instrument',
+        '--no-source-map',
+        process.execPath,
+        './env.js'
+      ]
+      var expected = {
+        silent: true,
+        instrument: false,
+        sourceMap: false,
+        instrumenter: './lib/instrumenters/noop'
+      }
+
+      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)
+        var env = JSON.parse(stdout)
+        var config = JSON.parse(env.NYC_CONFIG, null, 2)
+        config.should.include(expected)
+        done()
+      })
+    })
+
+    describe('--all', function () {
+      it('extracts coverage headers from unexecuted files', function (done) {
+        var nycOutput = path.resolve(fixturesCLI, '.nyc_output')
+        rimraf.sync(nycOutput)
+
+        var args = [
+          bin,
+          '--all',
+          '--silent',
+          '--no-instrument',
+          '--no-source-map',
+          process.execPath,
+          // any file other than external-instrument.js, which we
+          // want to ensure has its header loaded.
+          './env.js'
+        ]
+
+        var proc = spawn(process.execPath, args, {
+          cwd: fixturesCLI,
+          env: env
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(0)
+          glob(nycOutput + '/*.json', function (_err, files) {
+            // we should have extracted the coverage header from external-instrumenter.js.
+            var coverage = {}
+            files.forEach(function (file) {
+              _.assign(coverage, JSON.parse(
+                fs.readFileSync(file, 'utf-8')
+              ))
+            })
+            Object.keys(coverage).should.include('./external-instrumenter.js')
+
+            // we should not have executed file, so all counts sould be 0.
+            var sum = 0
+            Object.keys(coverage['./external-instrumenter.js'].s).forEach(function (k) {
+              sum += coverage['./external-instrumenter.js'].s[k]
+            })
+            sum.should.equal(0)
+
+            return done()
+          })
+        })
+      })
+    })
+  })
+
+  it('allows an alternative cache folder to be specified', function (done) {
+    var args = [bin, '--cache-dir=./foo-cache', '--cache=true', process.execPath, './half-covered.js']
+
+    var proc = spawn(process.execPath, args, {
+      cwd: fixturesCLI,
+      env: env
+    })
+    proc.on('close', function (code) {
+      code.should.equal(0)
+      // we should have created ./foo-cache rather
+      // than the default ./node_modules/.cache.
+      fs.readdirSync(path.resolve(
+        fixturesCLI, './foo-cache'
+      )).length.should.equal(1)
+      rimraf.sync(path.resolve(fixturesCLI, 'foo-cache'))
+      done()
+    })
+  })
+
+  // see: https://github.com/istanbuljs/nyc/issues/563
+  it('does not create .cache folder if cache is "false"', function (done) {
+    var args = [bin, '--cache=false', process.execPath, './index.js']
+
+    var proc = spawn(process.execPath, args, {
+      cwd: process.cwd(),
+      env: env
+    })
+
+    rimraf.sync('./node_modules/.cache')
+
+    proc.on('close', function (code) {
+      code.should.equal(0)
+      fs.existsSync('./node_modules/.cache').should.equal(false)
+      done()
+    })
+  })
+
+  it('allows alternative high and low watermarks to be configured', function (done) {
+    var args = [
+      bin,
+      '--watermarks.lines=90',
+      '--watermarks.lines=100',
+      '--watermarks.statements=30',
+      '--watermarks.statements=40',
+      '--cache=true',
+      process.execPath,
+      './half-covered.js'
+    ]
+
+    var proc = spawn(process.execPath, args, {
+      cwd: fixturesCLI,
+      env: {
+        PATH: process.env.PATH,
+        FORCE_COLOR: true
+      }
+    })
+
+    var stdout = ''
+    proc.stdout.on('data', function (chunk) {
+      stdout += chunk
+    })
+
+    proc.on('close', function (code) {
+      code.should.equal(0)
+      // 50% line coverage is below our low watermark (so it's red).
+      stdout.should.match(/\[31;1m\W+50\W+/)
+      // 50% statement coverage is above our high-watermark (so it's green).
+      stdout.should.match(/\[32;1m\W+50\W+/)
+      done()
+    })
+  })
+
+  // the following tests exercise nyc's behavior around source-maps
+  // that have been included with pre-instrumented files. Perhaps, as an
+  // example, unit tests are being run against minified JavaScript.
+  // --exclude-after-remap will likely need to be set to false when
+  // using nyc with this type of configuration.
+  describe('source-maps', () => {
+    describe('--all', () => {
+      it('includes files with both .map files and inline source-maps', (done) => {
+        const args = [
+          bin,
+          '--all',
+          '--cache', 'false',
+          '--exclude-after-remap', 'false',
+          '--exclude', 'original',
+          process.execPath, './instrumented/s1.min.js'
+        ]
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesSourceMaps,
+          env: env
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(0)
+          stdoutShouldEqual(stdout, `
+            ----------|----------|----------|----------|----------|-------------------|
+            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+            ----------|----------|----------|----------|----------|-------------------|
+            All files |    44.44 |      100 |    33.33 |    44.44 |                   |
+             s1.js    |       80 |      100 |       50 |       80 |                 7 |
+             s2.js    |        0 |      100 |        0 |        0 |           1,2,4,6 |
+            ----------|----------|----------|----------|----------|-------------------|`
+          )
+          done()
+        })
+      })
+
+      it('uses source-maps to exclude original sources from reports', (done) => {
+        const args = [
+          bin,
+          '--all',
+          '--cache', 'false',
+          '--exclude', 'original/s1.js',
+          process.execPath, './instrumented/s1.min.js'
+        ]
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesSourceMaps,
+          env: env
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(0)
+          stdoutShouldEqual(stdout, `
+            ----------|----------|----------|----------|----------|-------------------|
+            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+            ----------|----------|----------|----------|----------|-------------------|
+            All files |        0 |      100 |        0 |        0 |                   |
+             s2.js    |        0 |      100 |        0 |        0 |           1,2,4,6 |
+            ----------|----------|----------|----------|----------|-------------------|`
+          )
+          done()
+        })
+      })
+    })
+
+    describe('.map file', () => {
+      it('appropriately instruments file with corresponding .map file', (done) => {
+        const args = [
+          bin,
+          '--cache', 'false',
+          '--exclude-after-remap', 'false',
+          '--exclude', 'original',
+          process.execPath, './instrumented/s1.min.js'
+        ]
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesSourceMaps,
+          env: env
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(0)
+          stdoutShouldEqual(stdout, `
+          ----------|----------|----------|----------|----------|-------------------|
+          File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+          ----------|----------|----------|----------|----------|-------------------|
+          All files |       80 |      100 |       50 |       80 |                   |
+           s1.js    |       80 |      100 |       50 |       80 |                 7 |
+          ----------|----------|----------|----------|----------|-------------------|`)
+          done()
+        })
+      })
+    })
+
+    describe('inline', () => {
+      it('appropriately instruments a file with an inline source-map', (done) => {
+        const args = [
+          bin,
+          '--cache', 'false',
+          '--exclude-after-remap', 'false',
+          '--exclude', 'original',
+          process.execPath, './instrumented/s2.min.js'
+        ]
+
+        const proc = spawn(process.execPath, args, {
+          cwd: fixturesSourceMaps,
+          env: env
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', function (code) {
+          code.should.equal(0)
+          stdoutShouldEqual(stdout, `
+            ----------|----------|----------|----------|----------|-------------------|
+            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+            ----------|----------|----------|----------|----------|-------------------|
+            All files |      100 |      100 |      100 |      100 |                   |
+             s2.js    |      100 |      100 |      100 |      100 |                   |
+            ----------|----------|----------|----------|----------|-------------------|`)
+          done()
+        })
+      })
+    })
+  })
+
+  describe('skip-empty', () => {
+    it('does not display 0-line files in coverage output', (done) => {
+      const args = [
+        bin,
+        '--cache', 'false',
+        '--skip-empty', 'true',
+        process.execPath, './empty.js'
+      ]
+
+      const proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      var stdout = ''
+      proc.stdout.on('data', function (chunk) {
+        stdout += chunk
+      })
+
+      proc.stdout.on('error', function (chunk) {
+        stdout += chunk
+      })
+
+      proc.on('close', function (code) {
+        code.should.equal(0)
+        stdoutShouldEqual(stdout, `
+        ----------|----------|----------|----------|----------|-------------------|
+        File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+        ----------|----------|----------|----------|----------|-------------------|
+        ----------|----------|----------|----------|----------|-------------------|`)
+        done()
+      })
+    })
+  })
+
+  describe('skip-full', () => {
+    it('does not display files with 100% statement, branch, and function coverage', (done) => {
+      const args = [
+        bin,
+        '--skip-full',
+        process.execPath, './skip-full.js'
+      ]
+
+      const 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)
+        stdoutShouldEqual(stdout, `
+        -----------------|----------|----------|----------|----------|-------------------|
+        File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+        -----------------|----------|----------|----------|----------|-------------------|
+        All files        |     62.5 |       50 |      100 |     62.5 |                   |
+         half-covered.js |       50 |       50 |      100 |       50 |             6,7,8 |
+        -----------------|----------|----------|----------|----------|-------------------|`)
+        done()
+      })
+    })
+  })
+
+  describe('es-modules', () => {
+    it('allows reserved word when es-modules is disabled', (done) => {
+      const args = [
+        bin,
+        '--cache', 'false',
+        '--es-modules', 'false',
+        process.execPath, './not-strict.js'
+      ]
+
+      const 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)
+        stdoutShouldEqual(stdout, `
+        ---------------|----------|----------|----------|----------|-------------------|
+        File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+        ---------------|----------|----------|----------|----------|-------------------|
+        All files      |      100 |      100 |      100 |      100 |                   |
+         not-strict.js |      100 |      100 |      100 |      100 |                   |
+        ---------------|----------|----------|----------|----------|-------------------|`)
+        done()
+      })
+    })
+
+    it('forbids reserved word when es-modules is not disabled', (done) => {
+      const args = [
+        bin,
+        '--cache', 'false',
+        '--exit-on-error', 'true',
+        process.execPath, './not-strict.js'
+      ]
+
+      const proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      var stdout = ''
+      proc.stdout.on('data', function (chunk) {
+        stdout += chunk
+      })
+
+      var stderr = ''
+      proc.stderr.on('data', function (chunk) {
+        stderr += chunk
+      })
+
+      proc.on('close', function (code) {
+        code.should.equal(1)
+        stdoutShouldEqual(stderr, `
+        Failed to instrument ${path.join(fixturesCLI, 'not-strict.js')}`)
+        stdoutShouldEqual(stdout, `
+        ----------|----------|----------|----------|----------|-------------------|
+        File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+        ----------|----------|----------|----------|----------|-------------------|
+        All files |        0 |        0 |        0 |        0 |                   |
+        ----------|----------|----------|----------|----------|-------------------|`)
+        done()
+      })
+    })
+  })
+
+  describe('merge', () => {
+    it('combines multiple coverage reports', (done) => {
+      const args = [
+        bin,
+        'merge',
+        './merge-input'
+      ]
+
+      const proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      proc.on('close', function (code) {
+        const mergedCoverage = require('./fixtures/cli/coverage')
+        // the combined reports should have 100% function
+        // branch and statement coverage.
+        mergedCoverage['/private/tmp/contrived/library.js']
+          .s.should.eql({ '0': 2, '1': 1, '2': 1, '3': 2, '4': 1, '5': 1 })
+        mergedCoverage['/private/tmp/contrived/library.js']
+          .f.should.eql({ '0': 1, '1': 1, '2': 2 })
+        mergedCoverage['/private/tmp/contrived/library.js']
+          .b.should.eql({ '0': [1, 1] })
+        rimraf.sync(path.resolve(fixturesCLI, 'coverage.json'))
+        return done()
+      })
+    })
+
+    it('reports error if input directory is missing', (done) => {
+      const args = [
+        bin,
+        'merge',
+        './DIRECTORY_THAT_IS_MISSING'
+      ]
+
+      const proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      var stderr = ''
+      proc.stderr.on('data', function (chunk) {
+        stderr += chunk
+      })
+
+      proc.on('close', function (code) {
+        stderr.should.match(/failed access input directory/)
+        return done()
+      })
+    })
+
+    it('reports error if input is not a directory', (done) => {
+      const args = [
+        bin,
+        'merge',
+        './package.json'
+      ]
+
+      const proc = spawn(process.execPath, args, {
+        cwd: fixturesCLI,
+        env: env
+      })
+
+      var stderr = ''
+      proc.stderr.on('data', function (chunk) {
+        stderr += chunk
+      })
+
+      proc.on('close', function (code) {
+        stderr.should.match(/was not a directory/)
+        return done()
+      })
+    })
+  })
+
+  describe('exclude-node-modules', () => {
+    const fixturesENM = path.resolve(__dirname, './fixtures/exclude-node-modules')
+    const globalArgs = [
+      bin,
+      '--all=true',
+      '--cache=false',
+      '--per-file=true',
+      '--exclude-node-modules=false',
+      '--include=node_modules/@istanbuljs/fake-module-1/**'
+    ]
+    const spawnOpts = {
+      cwd: fixturesENM,
+      env: env
+    }
+    const noCoverageError = `ERROR: Coverage for lines (0%) does not meet threshold (90%) for ${path.join(fixturesENM, 'node_modules/@istanbuljs/fake-module-1/index.js')}\n`
+
+    it('execute', done => {
+      function checkReport (code, stderr, stdout, next) {
+        code.should.equal(1)
+        stderr.should.equal(noCoverageError)
+        stdoutShouldEqual(stdout, `
+          ----------|----------|----------|----------|----------|-------------------|
+          File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+          ----------|----------|----------|----------|----------|-------------------|
+          All files |        0 |      100 |      100 |        0 |                   |
+           index.js |        0 |      100 |      100 |        0 |                 1 |
+          ----------|----------|----------|----------|----------|-------------------|`)
+        next()
+      }
+
+      function executeMainCommand () {
+        const args = [
+          ...globalArgs,
+          '--check-coverage=true',
+          process.execPath, './bin/do-nothing.js'
+        ]
+
+        const proc = spawn(process.execPath, args, spawnOpts)
+
+        var stderr = ''
+        proc.stderr.on('data', function (chunk) {
+          stderr += chunk
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', code => checkReport(code, stderr, stdout, executeReport))
+      }
+
+      function executeReport () {
+        const args = [
+          ...globalArgs,
+          '--check-coverage=true',
+          'report'
+        ]
+
+        const proc = spawn(process.execPath, args, spawnOpts)
+
+        var stderr = ''
+        proc.stderr.on('data', function (chunk) {
+          stderr += chunk
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', code => checkReport(code, stderr, stdout, executeCheckCoverage))
+      }
+
+      function executeCheckCoverage () {
+        const args = [
+          ...globalArgs,
+          'check-coverage'
+        ]
+
+        const proc = spawn(process.execPath, args, spawnOpts)
+
+        var stderr = ''
+        proc.stderr.on('data', function (chunk) {
+          stderr += chunk
+        })
+
+        var stdout = ''
+        proc.stdout.on('data', function (chunk) {
+          stdout += chunk
+        })
+
+        proc.on('close', code => {
+          code.should.equal(1)
+          stderr.should.equal(noCoverageError)
+          stdoutShouldEqual(stdout, '')
+          done()
+        })
+      }
+
+      executeMainCommand()
+    })
+
+    it('instrument', done => {
+      const args = [
+        ...globalArgs,
+        'instrument',
+        'node_modules'
+      ]
+
+      const proc = spawn(process.execPath, args, spawnOpts)
+
+      var stderr = ''
+      proc.stderr.on('data', function (chunk) {
+        stderr += chunk
+      })
+
+      var stdout = ''
+      proc.stdout.on('data', function (chunk) {
+        stdout += chunk
+      })
+
+      proc.on('close', code => {
+        code.should.equal(0)
+        stderr.should.equal('')
+        stdout.should.match(/fake-module-1/)
+        stdout.should.not.match(/fake-module-2/)
+        done()
+      })
+    })
+  })
+
+  it('recursive run does not throw', done => {
+    const args = [
+      bin,
+      process.execPath,
+      bin,
+      process.execPath,
+      bin,
+      process.execPath,
+      bin,
+      'true'
+    ]
+    const proc = spawn(process.execPath, args, {
+      cwd: path.resolve(__dirname, './fixtures/recursive-run')
+    })
+
+    let stdio = ''
+    proc.stderr.on('data', chunk => {
+      stdio += chunk
+    })
+
+    proc.stdout.on('data', chunk => {
+      stdio += chunk
+    })
+
+    proc.on('close', code => {
+      code.should.equal(0)
+      stdio.should.equal('')
+      done()
+    })
+  })
+})
+
+function stdoutShouldEqual (stdout, expected) {
+  `\n${stdout}`.should.equal(`${si(expected)}\n`)
+}
diff --git a/test/nyc-integration.js b/test/nyc-integration.js
index 58fa87d..54f34da 100644
--- a/test/nyc-integration.js
+++ b/test/nyc-integration.js
@@ -1,1978 +1,188 @@
-/* global describe, it, beforeEach, afterEach */
+'use strict'
 
-const _ = require('lodash')
 const path = require('path')
-const bin = path.resolve(__dirname, '../self-coverage/bin/nyc')
-const fixturesCLI = path.resolve(__dirname, './fixtures/cli')
-const fixturesHooks = path.resolve(__dirname, './fixtures/hooks')
-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')
+const os = require('os')
 
-require('chai').should()
-require('tap').mochaGlobals()
+const t = require('tap')
 
-// beforeEach
-rimraf.sync(path.resolve(fakebin, 'node'))
-rimraf.sync(path.resolve(fakebin, 'npm'))
-rimraf.sync(path.resolve(fixturesCLI, 'subdir', 'output-dir'))
+const { fixturesCLI, runNYC, tempDirSetup, testSuccess, testFailure } = require('./helpers')
 
-describe('the nyc cli', function () {
-  var env = { PATH: process.env.PATH }
+const nycConfigJS = path.resolve(fixturesCLI, 'nyc-config-js')
+const nycrcDir = path.resolve(fixturesCLI, 'nycrc')
 
-  describe('--include', function () {
-    it('can be used to limit bin to instrumenting specific files', function (done) {
-      var args = [bin, '--all', '--include', 'half-covered.js', 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(/half-covered\.js/)
-        stdout.should.not.match(/half-covered-failing\.js/)
-        stdout.should.not.match(/test\.js/)
-        done()
-      })
-    })
-  })
-
-  describe('report and check', function () {
-    it('should show coverage check along with report', function (done) {
-      // generate some coverage info
-      var args = [bin, '--silent', process.execPath, './half-covered.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        var args = [bin, 'report', '--check-coverage', '--lines=100']
-        var proc = spawn(process.execPath, args, {
-          cwd: fixturesCLI,
-          env: env
-        })
-
-        var stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.not.equal(0)
-          stderr.should.equal('ERROR: Coverage for lines (50%) does not meet global threshold (100%)\n')
-          done()
-        })
-      })
-    })
-  })
-
-  describe('--exclude', function () {
-    it('should allow default exclude rules to be overridden', function (done) {
-      var args = [bin, '--all', '--exclude', '**/half-covered.js', 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.not.match(/half-covered\.js/)
-        stdout.should.match(/test\.js/)
-        done()
-      })
-    })
-  })
-
-  describe('--ignore-class-method', function () {
-    it('skips methods that match ignored name but still catches those that are not', function (done) {
-      var args = [bin, '--all', '--ignore-class-method', 'skip', process.execPath, './classes.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)
-        var classesOutput = (stdout.match(/^(.*classes\.js).*$/m) || ['no result found'])[0]
-        classesOutput.should.match(/6 \|/)
-        done()
-      })
-    })
-  })
-
-  describe('--check-coverage', function () {
-    it('fails when the expected coverage is below a threshold', function (done) {
-      var args = [bin, '--check-coverage', '--lines', '51', process.execPath, './half-covered.js']
-      var message = 'ERROR: Coverage for lines (50%) does not meet global threshold (51%)'
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.not.equal(0)
-        stderr.trim().should.equal(message)
-        done()
-      })
-    })
-
-    // https://github.com/istanbuljs/nyc/issues/384
-    it('fails when check-coverage command is used rather than flag', function (done) {
-      var args = [bin, 'check-coverage', '--lines', '51', process.execPath, './half-covered.js']
-      var message = 'ERROR: Coverage for lines (50%) does not meet global threshold (51%)'
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.not.equal(0)
-        stderr.trim().should.equal(message)
-        done()
-      })
-    })
-
-    it('succeeds when the expected coverage is above a threshold', function (done) {
-      var args = [bin, '--check-coverage', '--lines', '49', process.execPath, './half-covered.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        done()
-      })
-    })
-
-    // https://github.com/bcoe/nyc/issues/209
-    it('fails in any case when the underlying test failed', function (done) {
-      var args = [bin, '--check-coverage', '--lines', '49', process.execPath, './half-covered-failing.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('close', function (code) {
-        code.should.not.equal(0)
-        done()
-      })
-    })
-
-    it('fails when the expected file coverage is below a threshold', function (done) {
-      var args = [bin, '--check-coverage', '--lines', '51', '--per-file', process.execPath, './half-covered.js']
-      var matcher = RegExp('ERROR: Coverage for lines \\(50%\\) does not meet threshold \\(51%\\) for .+half-covered.js')
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.not.equal(0)
-        stderr.trim().should.match(matcher)
-        done()
-      })
-    })
-  })
-
-  // 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('configuration', function () {
-    it('passes configuration via environment variables', function (done) {
-      var args = [
-        bin,
-        '--silent',
-        '--require=make-dir',
-        '--include=env.js',
-        '--exclude=batman.js',
-        '--extension=.js',
-        '--cache=false',
-        '--cache-dir=/tmp',
-        '--source-map=true',
-        process.execPath,
-        './env.js'
-      ]
-      var expected = {
-        instrumenter: './lib/instrumenters/istanbul',
-        silent: true,
-        cacheDir: '/tmp',
-        cache: false,
-        sourceMap: true
-      }
-
-      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)
-        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()
-      })
-    })
-
-    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()
-      })
-    })
-
-    describe('nyc.config.js', function () {
-      var cwd = path.resolve(fixturesCLI, './nyc-config-js')
-
-      it('loads configuration from package.json and nyc.config.js', function (done) {
-        var args = [bin, process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.not.match(/SF:.*ignore\.js/)
-          stdout.should.not.match(/SF:.*nyc\.config\.js/)
-          stdout.should.not.match(/SF:.*nycrc-config\.js/)
-          done()
-        })
-      })
-
-      it('loads configuration from different module rather than nyc.config.js', function (done) {
-        var args = [bin, '--all', '--nycrc-path', './nycrc-config.js', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          // should be 1 due to coverage check
-          code.should.equal(1)
-          stdout.should.match(/SF:.*index\.js/)
-          stdout.should.match(/SF:.*ignore\.js/)
-          stdout.should.match(/SF:.*nyc\.config\.js/)
-          stdout.should.match(/SF:.*nycrc-config\.js/)
-          done()
-        })
-      })
-
-      it('allows nyc.config.js configuration to be overridden with command line args', function (done) {
-        var args = [bin, '--all', '--exclude=foo.js', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.match(/SF:.*ignore\.js/)
-          stdout.should.match(/SF:.*nyc\.config\.js/)
-          stdout.should.match(/SF:.*nycrc-config\.js/)
-          done()
-        })
-      })
-    })
-
-    describe('.nycrc', function () {
-      var cwd = path.resolve(fixturesCLI, './nycrc')
-
-      it('loads configuration from package.json and .nycrc', function (done) {
-        var args = [bin, process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.not.match(/SF:.*ignore\.js/)
-          done()
-        })
-      })
-
-      it('loads configuration from different file rather than .nycrc', function (done) {
-        var args = [bin, '--nycrc-path', './.nycrc-config.json', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          // should be 1 due to coverage check
-          code.should.equal(1)
-          stdout.should.match(/SF:.*index\.js/)
-          stdout.should.match(/SF:.*ignore\.js/)
-          done()
-        })
-      })
-
-      it('loads configuration from .nycrc.yml', function (done) {
-        var args = [bin, '--nycrc-path', './.nycrc.yml', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.not.match(/SF:.*ignore\.js/)
-          done()
-        })
-      })
-
-      it('loads configuration from .nycrc.yaml', function (done) {
-        var args = [bin, '--nycrc-path', './.nycrc.yaml', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.not.match(/SF:.*ignore\.js/)
-          done()
-        })
-      })
-
-      it('allows .nycrc configuration to be overridden with command line args', function (done) {
-        var args = [bin, '--exclude=foo.js', process.execPath, './index.js']
-
-        var proc = spawn(process.execPath, args, {
-          cwd: cwd,
-          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:.*index\.js/)
-          stdout.should.match(/SF:.*ignore\.js/)
-          done()
-        })
-      })
-    })
-  })
-
-  describe('coverage', function () {
-    it('reports appropriate coverage information for es6 source files', function (done) {
-      var args = [bin, '--reporter=lcov', '--reporter=text', process.execPath, './es6.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)
-        // we should miss covering the appropriate lines.
-        stdout.should.match(/11,16,17/)
-        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 <input> to <output> as well as those that have been instrumented', function (done) {
-        const args = [bin, 'instrument', '--complete-copy', './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.include('package.json')
-          files.should.include('node_modules')
-          const includeTarget = path.resolve(fixturesCLI, 'output', 'ignore.js')
-          fs.readFileSync(includeTarget, 'utf8')
-            .should.match(/var cov_/)
-          done()
-        })
-      })
-
-      it('can instrument the project directory', function (done) {
-        const args = [bin, 'instrument', '.', './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('args.js')
-          files.should.include('subdir')
-          done()
-        })
-      })
-
-      it('allows a sub-directory of files to be instrumented', function (done) {
-        const args = [bin, 'instrument', './subdir/input-dir', './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')
-          done()
-        })
-      })
-
-      it('allows a subdirectory to be excluded via .nycrc file', function (done) {
-        const args = [bin, 'instrument', '--nycrc-path', './.instrument-nycrc', './subdir/input-dir', './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.length.should.not.equal(0)
-          files.should.include('exclude-me')
-          files.should.include('node_modules')
-          files.should.include('index.js')
-          files.should.include('bad.js')
-          const includeTarget = path.resolve(fixturesCLI, 'output', 'index.js')
-          fs.readFileSync(includeTarget, 'utf8')
-            .should.match(/var cov_/)
-          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
-          fs.readFileSync(excludeTarget, 'utf8')
-            .should.not.match(/var cov_/)
-          done()
-        })
-      })
-
-      it('allows a file to be excluded', function (done) {
-        const args = [bin, 'instrument', '--complete-copy', '--exclude', 'exclude-me/index.js', './subdir/input-dir', './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.length.should.not.equal(0)
-          files.should.include('exclude-me')
-          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
-          fs.readFileSync(excludeTarget, 'utf8')
-            .should.not.match(/var cov_/)
-          done()
-        })
-      })
-
-      it('allows specifying a single sub-directory to be included', function (done) {
-        const args = [bin, 'instrument', '--include', '**/include-me/**', './subdir/input-dir', './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.length.should.not.equal(0)
-          files.should.include('include-me')
-          const instrumented = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
-          fs.readFileSync(instrumented, 'utf8')
-            .should.match(/var cov_/)
-          done()
-        })
-      })
-
-      it('allows a file to be excluded from an included directory', function (done) {
-        const args = [bin, 'instrument', '--complete-copy', '--exclude', '**/exclude-me.js', '--include', '**/include-me/**', './subdir/input-dir', './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.length.should.not.equal(0)
-          files.should.include('include-me')
-          const includeMeFiles = fs.readdirSync(path.resolve(fixturesCLI, 'output', 'include-me'))
-          includeMeFiles.length.should.not.equal(0)
-          includeMeFiles.should.include('include-me.js')
-          includeMeFiles.should.include('exclude-me.js')
-          const includeTarget = path.resolve(fixturesCLI, 'output', 'include-me', 'include-me.js')
-          fs.readFileSync(includeTarget, 'utf8')
-            .should.match(/var cov_/)
-          const excludeTarget = path.resolve(fixturesCLI, 'output', 'exclude-me', 'index.js')
-          fs.readFileSync(excludeTarget, 'utf8')
-            .should.not.match(/var cov_/)
-          done()
-        })
-      })
-
-      it('aborts if trying to write files in place', function (done) {
-        const args = [bin, 'instrument', '--delete', './', './']
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesCLI,
-          env: env
-        })
-
-        let stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(1)
-          stderr.should.include('nyc instrument failed: cannot instrument files in place')
-          done()
-        })
-      })
-
-      it('aborts if trying to instrument files from outside the project root directory', function (done) {
-        const args = [bin, 'instrument', '--delete', '../', './']
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesCLI,
-          env: env
-        })
-
-        let stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(1)
-          stderr.should.include('nyc instrument failed: cannot instrument files outside of project root directory')
-          done()
-        })
-      })
-
-      describe('es-modules', function () {
-        afterEach(function () {
-          rimraf.sync(path.resolve(fixturesCLI, './output'))
-        })
-
-        it('instruments file with `package` keyword when es-modules is disabled', function (done) {
-          const args = [bin, 'instrument', '--no-es-modules', './not-strict.js', './output']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(0)
-            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
-            subdirExists.should.equal(true)
-            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
-            files.should.include('not-strict.js')
-            done()
-          })
-        })
-
-        it('fails on file with `package` keyword when es-modules is enabled', function (done) {
-          const args = [bin, 'instrument', '--exit-on-error', './not-strict.js', './output']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          let stderr = ''
-          proc.stderr.on('data', function (chunk) {
-            stderr += chunk
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(1)
-            stdoutShouldEqual(stderr, `
-              Failed to instrument ${path.resolve(fixturesCLI, 'not-strict.js')}`)
-            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
-            subdirExists.should.equal(false)
-            done()
-          })
-        })
-      })
-
-      describe('delete', function () {
-        beforeEach(function () {
-          makeDir.sync(path.resolve(fixturesCLI, 'output', 'removed-by-clean'))
-        })
-
-        it('cleans the output directory if `--delete` is specified', function (done) {
-          const args = [bin, 'instrument', '--delete', 'true', './subdir/input-dir', './output']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(0)
-            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
-            subdirExists.should.equal(true)
-            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
-            files.should.not.include('removed-by-clean')
-            files.should.include('exclude-me')
-            done()
-          })
-        })
-
-        it('does not clean the output directory by default', function (done) {
-          const args = [bin, 'instrument', './subdir/input-dir', './output']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(0)
-            const subdirExists = fs.existsSync(path.resolve(fixturesCLI, './output'))
-            subdirExists.should.equal(true)
-            const files = fs.readdirSync(path.resolve(fixturesCLI, './output'))
-            files.should.include('removed-by-clean')
-            done()
-          })
-        })
-
-        it('aborts if trying to clean process.cwd()', function (done) {
-          const args = [bin, 'instrument', '--delete', './src', './']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          let stderr = ''
-          proc.stderr.on('data', function (chunk) {
-            stderr += chunk
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(1)
-            stderr.should.include('nyc instrument failed: attempt to delete')
-            done()
-          })
-        })
-
-        it('aborts if trying to clean outside working directory', function (done) {
-          const args = [bin, 'instrument', '--delete', './', '../']
-
-          const proc = spawn(process.execPath, args, {
-            cwd: fixturesCLI,
-            env: env
-          })
-
-          let stderr = ''
-          proc.stderr.on('data', function (chunk) {
-            stderr += chunk
-          })
-
-          proc.on('close', function (code) {
-            code.should.equal(1)
-            stderr.should.include('nyc instrument failed: attempt to delete')
-            done()
-          })
-        })
-      })
-    })
-  })
-
-  describe('hooks', function () {
-    it('provides coverage for requireJS and AMD modules', function (done) {
-      var args = [bin, '--hook-run-in-this-context', '--hook-require=false', process.execPath, './index.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesHooks,
-        env: process.env
-      })
-      var stdout = ''
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        stdout.should.match(/ipsum\.js/)
-        stdout.should.match(/lorem\.js/)
-        done()
-      })
-    })
-  })
-
-  it('help shows to stderr when main command doesn\'t know what to do', () => {
-    const opts = {
-      cwd: fixturesCLI,
-      env,
-      encoding: 'utf8'
-    }
-
-    const help = spawnSync(process.execPath, [bin, '--help'], opts)
-    const unknown = spawnSync(process.execPath, [bin], opts)
-    help.status.should.equal(0)
-    unknown.status.should.equal(1)
-    help.stderr.should.equal('')
-    unknown.stdout.should.equal('')
-    help.stdout.should.not.equal('')
-    help.stdout.should.equal(unknown.stderr)
-  })
-
-  describe('args', function () {
-    it('does not interpret args intended for instrumented bin', function (done) {
-      var args = [bin, '--silent', process.execPath, 'args.js', '--help', '--version']
-
-      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)
-        var args = JSON.parse(stdout)
-        args.should.include('--help')
-        args.should.include('--version')
-        args.should.not.include('--silent')
-        done()
-      })
-    })
-
-    it('interprets first args after -- as Node.js execArgv', function (done) {
-      var args = [bin, '--', '--expose-gc', path.resolve(fixturesCLI, 'gc.js')]
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stdout = ''
-      proc.stdout.setEncoding('utf8')
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        stdout.should.include('still running')
-        done()
-      })
-    })
-  })
-
-  describe('--show-process-tree', function () {
-    it('displays a tree of spawned processes', function (done) {
-      var args = [bin, '--show-process-tree', process.execPath, 'selfspawn-fibonacci.js', '5']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stdout = ''
-      proc.stdout.setEncoding('utf8')
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        stdout.should.match(new RegExp(
-          'nyc\n' +
-          '└─┬.*selfspawn-fibonacci.js 5\n' +
-          '  │.* % Lines\n' +
-          '  ├─┬.*selfspawn-fibonacci.js 4\n' +
-          '  │ │.* % Lines\n' +
-          '  │ ├─┬.*selfspawn-fibonacci.js 3\n' +
-          '  │ │ │.* % Lines\n' +
-          '  │ │ ├──.*selfspawn-fibonacci.js 2\n' +
-          '  │ │ │.* % Lines\n' +
-          '  │ │ └──.*selfspawn-fibonacci.js 1\n' +
-          '  │ │    .* % Lines\n' +
-          '  │ └──.*selfspawn-fibonacci.js 2\n' +
-          '  │    .* % Lines\n' +
-          '  └─┬.*selfspawn-fibonacci.js 3\n' +
-          '    │.* % Lines\n' +
-          '    ├──.*selfspawn-fibonacci.js 2\n' +
-          '    │.* % Lines\n' +
-          '    └──.*selfspawn-fibonacci.js 1\n' +
-          '       .* % Lines\n'
-        ))
-        done()
-      })
-    })
-  })
-
-  describe('--temp-dir', function () {
-    beforeEach(() => {
-      rimraf.sync(path.resolve(fixturesCLI, '.nyc_output'))
-      rimraf.sync(path.resolve(fixturesCLI, '.temp_directory'))
-      rimraf.sync(path.resolve(fixturesCLI, '.temp_dir'))
-    })
-
-    it('creates the default \'tempDir\' when none is specified', function (done) {
-      var args = [bin, process.execPath, './half-covered.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.nyc_output'))
-        tempFiles.length.should.equal(2) // the coverage file, and processinfo
-        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
-        cliFiles.should.include('.nyc_output')
-        cliFiles.should.not.include('.temp_dir')
-        cliFiles.should.not.include('.temp_directory')
-        done()
-      })
-    })
-
-    it('prefers \'tempDirectory\' to \'tempDir\'', function (done) {
-      var args = [bin, '--tempDirectory', '.temp_directory', '--tempDir', '.temp_dir', process.execPath, './half-covered.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('exit', function (code) {
-        code.should.equal(0)
-        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.temp_directory'))
-        tempFiles.length.should.equal(2)
-        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
-        cliFiles.should.not.include('.nyc_output')
-        cliFiles.should.not.include('.temp_dir')
-        cliFiles.should.include('.temp_directory')
-        done()
-      })
-    })
-
-    it('uses the \'tempDir\' option if \'tempDirectory\' is not set', function (done) {
-      var args = [bin, '--tempDir', '.temp_dir', process.execPath, './half-covered.js']
-
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('exit', function (code) {
-        code.should.equal(0)
-        var tempFiles = fs.readdirSync(path.resolve(fixturesCLI, '.temp_dir'))
-        tempFiles.length.should.equal(2)
-        var cliFiles = fs.readdirSync(path.resolve(fixturesCLI))
-        cliFiles.should.not.include('.nyc_output')
-        cliFiles.should.include('.temp_dir')
-        cliFiles.should.not.include('.temp_directory')
-        rimraf.sync(path.resolve(fixturesCLI, '.temp_dir'))
-        done()
-      })
-    })
-  })
-
-  it('handles --clean / --no-clean properly', () => {
-    rimraf.sync(path.resolve(fixturesCLI, '.nyc_output'))
-    const args = (doClean, arg) => [
-      bin,
-      doClean ? '--clean' : '--no-clean',
-      process.execPath,
-      './by-arg2.js',
-      arg
-    ]
-    const opts = {
-      cwd: fixturesCLI,
-      env: env,
-      encoding: 'utf8'
-    }
-
-    const proc1 = spawnSync(process.execPath, args(true, '1'), opts)
-    proc1.status.should.equal(0)
-    stdoutShouldEqual(proc1.stdout, `
-      1
-      ------------|----------|----------|----------|----------|-------------------|
-      File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-      ------------|----------|----------|----------|----------|-------------------|
-      All files   |       50 |       25 |      100 |       50 |                   |
-       by-arg2.js |       50 |       25 |      100 |       50 |             4,5,7 |
-      ------------|----------|----------|----------|----------|-------------------|`
-    )
-    proc1.stderr.should.equal('')
-
-    const proc2 = spawnSync(process.execPath, args(false, '2'), opts)
-    proc2.status.should.equal(0)
-    stdoutShouldEqual(proc2.stdout, `
-      2
-      ------------|----------|----------|----------|----------|-------------------|
-      File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-      ------------|----------|----------|----------|----------|-------------------|
-      All files   |    83.33 |       75 |      100 |    83.33 |                   |
-       by-arg2.js |    83.33 |       75 |      100 |    83.33 |                 7 |
-      ------------|----------|----------|----------|----------|-------------------|`
-    )
-    proc2.stderr.should.equal('')
-  })
-
-  describe('noop instrumenter', function () {
-    it('setting instrument to "false" configures noop instrumenter', function (done) {
-      var args = [
-        bin,
-        '--silent',
-        '--no-instrument',
-        '--no-source-map',
-        process.execPath,
-        './env.js'
-      ]
-      var expected = {
-        silent: true,
-        instrument: false,
-        sourceMap: false,
-        instrumenter: './lib/instrumenters/noop'
-      }
-
-      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)
-        var env = JSON.parse(stdout)
-        var config = JSON.parse(env.NYC_CONFIG, null, 2)
-        config.should.include(expected)
-        done()
-      })
-    })
-
-    describe('--all', function () {
-      it('extracts coverage headers from unexecuted files', function (done) {
-        var nycOutput = path.resolve(fixturesCLI, '.nyc_output')
-        rimraf.sync(nycOutput)
-
-        var args = [
-          bin,
-          '--all',
-          '--silent',
-          '--no-instrument',
-          '--no-source-map',
-          process.execPath,
-          // any file other than external-instrument.js, which we
-          // want to ensure has its header loaded.
-          './env.js'
-        ]
-
-        var proc = spawn(process.execPath, args, {
-          cwd: fixturesCLI,
-          env: env
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(0)
-          glob(nycOutput + '/*.json', function (_err, files) {
-            // we should have extracted the coverage header from external-instrumenter.js.
-            var coverage = {}
-            files.forEach(function (file) {
-              _.assign(coverage, JSON.parse(
-                fs.readFileSync(file, 'utf-8')
-              ))
-            })
-            Object.keys(coverage).should.include('./external-instrumenter.js')
-
-            // we should not have executed file, so all counts sould be 0.
-            var sum = 0
-            Object.keys(coverage['./external-instrumenter.js'].s).forEach(function (k) {
-              sum += coverage['./external-instrumenter.js'].s[k]
-            })
-            sum.should.equal(0)
-
-            return done()
-          })
-        })
-      })
-    })
-  })
-
-  it('allows an alternative cache folder to be specified', function (done) {
-    var args = [bin, '--cache-dir=./foo-cache', '--cache=true', process.execPath, './half-covered.js']
-
-    var proc = spawn(process.execPath, args, {
-      cwd: fixturesCLI,
-      env: env
-    })
-    proc.on('close', function (code) {
-      code.should.equal(0)
-      // we should have created ./foo-cache rather
-      // than the default ./node_modules/.cache.
-      fs.readdirSync(path.resolve(
-        fixturesCLI, './foo-cache'
-      )).length.should.equal(1)
-      rimraf.sync(path.resolve(fixturesCLI, 'foo-cache'))
-      done()
-    })
-  })
-
-  // see: https://github.com/istanbuljs/nyc/issues/563
-  it('does not create .cache folder if cache is "false"', function (done) {
-    var args = [bin, '--cache=false', process.execPath, './index.js']
-
-    var proc = spawn(process.execPath, args, {
-      cwd: process.cwd(),
-      env: env
-    })
+if (process.env.TAP_SNAPSHOT !== '1') {
+  t.jobs = os.cpus().length
+}
 
-    rimraf.sync('./node_modules/.cache')
+tempDirSetup(t, __filename)
+
+t.test('--include can be used to limit bin to instrumenting specific files', t => testSuccess(t, {
+  args: ['--all', '--include', 'half-covered.js', process.execPath, './half-covered.js']
+}))
+
+t.test('--exclude should allow default exclude rules to be overridden', t => testSuccess(t, {
+  args: [
+    '--all',
+    '--exclude=**/half-covered.js',
+    '--exclude=**/coverage',
+    process.execPath,
+    './half-covered.js'
+  ]
+}))
+
+t.test('report and check should show coverage check along with report', t => {
+  return testSuccess(t, {
+    args: ['--silent', process.execPath, './half-covered.js']
+  }).then(() => testFailure(t, {
+    args: ['report', '--check-coverage', '--lines=100']
+  }))
+})
 
-    proc.on('close', function (code) {
-      code.should.equal(0)
-      fs.existsSync('./node_modules/.cache').should.equal(false)
-      done()
-    })
-  })
+t.test('--ignore-class-method skips methods that match ignored name but still catches those that are not', t => testSuccess(t, {
+  args: ['--all', '--ignore-class-method', 'skip', process.execPath, './classes.js']
+}))
+
+t.test('--check-coverage fails when the expected coverage is below a threshold', t => testFailure(t, {
+  args: ['--check-coverage', '--lines', '51', process.execPath, './half-covered.js']
+}))
+
+// https://github.com/istanbuljs/nyc/issues/384
+t.test('--check-coverage fails when check-coverage command is used rather than flag', t => {
+  return testSuccess(t, {
+    args: [process.execPath, './half-covered.js']
+  }).then(() => testFailure(t, {
+    args: ['check-coverage', '--lines', '51', process.execPath, './half-covered.js']
+  }))
+})
 
-  it('allows alternative high and low watermarks to be configured', function (done) {
-    var args = [
-      bin,
-      '--watermarks.lines=90',
-      '--watermarks.lines=100',
-      '--watermarks.statements=30',
-      '--watermarks.statements=40',
-      '--cache=true',
+t.test('--check-coverage succeeds when the expected coverage is above a threshold', t => testSuccess(t, {
+  args: ['--check-coverage', '--lines', '49', process.execPath, './half-covered.js']
+}))
+
+// https://github.com/bcoe/nyc/issues/209
+t.test('--check-coverage fails in any case when the underlying test failed', t => testFailure(t, {
+  args: ['--check-coverage', '--lines', '49', process.execPath, './half-covered-failing.js']
+}))
+
+t.test('--check-coverage fails when the expected file coverage is below a threshold', t => testFailure(t, {
+  args: ['--check-coverage', '--lines', '51', '--per-file', process.execPath, './half-covered.js']
+}))
+
+t.test('passes configuration via environment variables', t => {
+  return runNYC({
+    tempDir: t.tempDir,
+    leavePathSep: true,
+    args: [
+      '--silent',
+      '--require=make-dir',
+      '--include=env.js',
+      '--exclude=batman.js',
+      '--extension=.js',
+      '--cache=false',
+      '--cache-dir=/tmp',
+      '--source-map=true',
       process.execPath,
-      './half-covered.js'
+      './env.js'
     ]
-
-    var proc = spawn(process.execPath, args, {
-      cwd: fixturesCLI,
-      env: {
-        PATH: process.env.PATH,
-        FORCE_COLOR: true
-      }
-    })
-
-    var stdout = ''
-    proc.stdout.on('data', function (chunk) {
-      stdout += chunk
-    })
-
-    proc.on('close', function (code) {
-      code.should.equal(0)
-      // 50% line coverage is below our low watermark (so it's red).
-      stdout.should.match(/\[31;1m\W+50\W+/)
-      // 50% statement coverage is above our high-watermark (so it's green).
-      stdout.should.match(/\[32;1m\W+50\W+/)
-      done()
-    })
-  })
-
-  // the following tests exercise nyc's behavior around source-maps
-  // that have been included with pre-instrumented files. Perhaps, as an
-  // example, unit tests are being run against minified JavaScript.
-  // --exclude-after-remap will likely need to be set to false when
-  // using nyc with this type of configuration.
-  describe('source-maps', () => {
-    describe('--all', () => {
-      it('includes files with both .map files and inline source-maps', (done) => {
-        const args = [
-          bin,
-          '--all',
-          '--cache', 'false',
-          '--exclude-after-remap', 'false',
-          '--exclude', 'original',
-          process.execPath, './instrumented/s1.min.js'
-        ]
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesSourceMaps,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(0)
-          stdoutShouldEqual(stdout, `
-            ----------|----------|----------|----------|----------|-------------------|
-            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-            ----------|----------|----------|----------|----------|-------------------|
-            All files |    44.44 |      100 |    33.33 |    44.44 |                   |
-             s1.js    |       80 |      100 |       50 |       80 |                 7 |
-             s2.js    |        0 |      100 |        0 |        0 |           1,2,4,6 |
-            ----------|----------|----------|----------|----------|-------------------|`
-          )
-          done()
-        })
-      })
-
-      it('uses source-maps to exclude original sources from reports', (done) => {
-        const args = [
-          bin,
-          '--all',
-          '--cache', 'false',
-          '--exclude', 'original/s1.js',
-          process.execPath, './instrumented/s1.min.js'
-        ]
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesSourceMaps,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(0)
-          stdoutShouldEqual(stdout, `
-            ----------|----------|----------|----------|----------|-------------------|
-            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-            ----------|----------|----------|----------|----------|-------------------|
-            All files |        0 |      100 |        0 |        0 |                   |
-             s2.js    |        0 |      100 |        0 |        0 |           1,2,4,6 |
-            ----------|----------|----------|----------|----------|-------------------|`
-          )
-          done()
-        })
-      })
-    })
-
-    describe('.map file', () => {
-      it('appropriately instruments file with corresponding .map file', (done) => {
-        const args = [
-          bin,
-          '--cache', 'false',
-          '--exclude-after-remap', 'false',
-          '--exclude', 'original',
-          process.execPath, './instrumented/s1.min.js'
-        ]
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesSourceMaps,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(0)
-          stdoutShouldEqual(stdout, `
-          ----------|----------|----------|----------|----------|-------------------|
-          File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-          ----------|----------|----------|----------|----------|-------------------|
-          All files |       80 |      100 |       50 |       80 |                   |
-           s1.js    |       80 |      100 |       50 |       80 |                 7 |
-          ----------|----------|----------|----------|----------|-------------------|`)
-          done()
-        })
-      })
-    })
-
-    describe('inline', () => {
-      it('appropriately instruments a file with an inline source-map', (done) => {
-        const args = [
-          bin,
-          '--cache', 'false',
-          '--exclude-after-remap', 'false',
-          '--exclude', 'original',
-          process.execPath, './instrumented/s2.min.js'
-        ]
-
-        const proc = spawn(process.execPath, args, {
-          cwd: fixturesSourceMaps,
-          env: env
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', function (code) {
-          code.should.equal(0)
-          stdoutShouldEqual(stdout, `
-            ----------|----------|----------|----------|----------|-------------------|
-            File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-            ----------|----------|----------|----------|----------|-------------------|
-            All files |      100 |      100 |      100 |      100 |                   |
-             s2.js    |      100 |      100 |      100 |      100 |                   |
-            ----------|----------|----------|----------|----------|-------------------|`)
-          done()
-        })
-      })
-    })
-  })
-
-  describe('skip-empty', () => {
-    it('does not display 0-line files in coverage output', (done) => {
-      const args = [
-        bin,
-        '--cache', 'false',
-        '--skip-empty', 'true',
-        process.execPath, './empty.js'
-      ]
-
-      const proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stdout = ''
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-
-      proc.stdout.on('error', function (chunk) {
-        stdout += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(0)
-        stdoutShouldEqual(stdout, `
-        ----------|----------|----------|----------|----------|-------------------|
-        File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-        ----------|----------|----------|----------|----------|-------------------|
-        ----------|----------|----------|----------|----------|-------------------|`)
-        done()
-      })
-    })
-  })
-
-  describe('skip-full', () => {
-    it('does not display files with 100% statement, branch, and function coverage', (done) => {
-      const args = [
-        bin,
-        '--skip-full',
-        process.execPath, './skip-full.js'
-      ]
-
-      const 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)
-        stdoutShouldEqual(stdout, `
-        -----------------|----------|----------|----------|----------|-------------------|
-        File             |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-        -----------------|----------|----------|----------|----------|-------------------|
-        All files        |     62.5 |       50 |      100 |     62.5 |                   |
-         half-covered.js |       50 |       50 |      100 |       50 |             6,7,8 |
-        -----------------|----------|----------|----------|----------|-------------------|`)
-        done()
-      })
-    })
-  })
-
-  describe('es-modules', () => {
-    it('allows reserved word when es-modules is disabled', (done) => {
-      const args = [
-        bin,
-        '--cache', 'false',
-        '--es-modules', 'false',
-        process.execPath, './not-strict.js'
-      ]
-
-      const 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)
-        stdoutShouldEqual(stdout, `
-        ---------------|----------|----------|----------|----------|-------------------|
-        File           |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-        ---------------|----------|----------|----------|----------|-------------------|
-        All files      |      100 |      100 |      100 |      100 |                   |
-         not-strict.js |      100 |      100 |      100 |      100 |                   |
-        ---------------|----------|----------|----------|----------|-------------------|`)
-        done()
-      })
-    })
-
-    it('forbids reserved word when es-modules is not disabled', (done) => {
-      const args = [
-        bin,
-        '--cache', 'false',
-        '--exit-on-error', 'true',
-        process.execPath, './not-strict.js'
-      ]
-
-      const proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stdout = ''
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        code.should.equal(1)
-        stdoutShouldEqual(stderr, `
-        Failed to instrument ${path.join(fixturesCLI, 'not-strict.js')}`)
-        stdoutShouldEqual(stdout, `
-        ----------|----------|----------|----------|----------|-------------------|
-        File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-        ----------|----------|----------|----------|----------|-------------------|
-        All files |        0 |        0 |        0 |        0 |                   |
-        ----------|----------|----------|----------|----------|-------------------|`)
-        done()
-      })
-    })
-  })
-
-  describe('merge', () => {
-    it('combines multiple coverage reports', (done) => {
-      const args = [
-        bin,
-        'merge',
-        './merge-input'
-      ]
-
-      const proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      proc.on('close', function (code) {
-        const mergedCoverage = require('./fixtures/cli/coverage')
-        // the combined reports should have 100% function
-        // branch and statement coverage.
-        mergedCoverage['/private/tmp/contrived/library.js']
-          .s.should.eql({ '0': 2, '1': 1, '2': 1, '3': 2, '4': 1, '5': 1 })
-        mergedCoverage['/private/tmp/contrived/library.js']
-          .f.should.eql({ '0': 1, '1': 1, '2': 2 })
-        mergedCoverage['/private/tmp/contrived/library.js']
-          .b.should.eql({ '0': [1, 1] })
-        rimraf.sync(path.resolve(fixturesCLI, 'coverage.json'))
-        return done()
-      })
-    })
-
-    it('reports error if input directory is missing', (done) => {
-      const args = [
-        bin,
-        'merge',
-        './DIRECTORY_THAT_IS_MISSING'
-      ]
-
-      const proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        stderr.should.match(/failed access input directory/)
-        return done()
-      })
-    })
-
-    it('reports error if input is not a directory', (done) => {
-      const args = [
-        bin,
-        'merge',
-        './package.json'
-      ]
-
-      const proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      proc.on('close', function (code) {
-        stderr.should.match(/was not a directory/)
-        return done()
-      })
-    })
-  })
-
-  describe('exclude-node-modules', () => {
-    const fixturesENM = path.resolve(__dirname, './fixtures/exclude-node-modules')
-    const globalArgs = [
-      bin,
-      '--all=true',
-      '--cache=false',
-      '--per-file=true',
-      '--exclude-node-modules=false',
-      '--include=node_modules/@istanbuljs/fake-module-1/**'
+  }).then(({ stdout, stderr, status }) => {
+    const checkOptions = [
+      'instrumenter',
+      'silent',
+      'cacheDir',
+      'cache',
+      'sourceMap',
+      'require',
+      'include',
+      'exclude',
+      'extension'
     ]
-    const spawnOpts = {
-      cwd: fixturesENM,
-      env: env
-    }
-    const noCoverageError = `ERROR: Coverage for lines (0%) does not meet threshold (90%) for ${path.join(fixturesENM, 'node_modules/@istanbuljs/fake-module-1/index.js')}\n`
-
-    it('execute', done => {
-      function checkReport (code, stderr, stdout, next) {
-        code.should.equal(1)
-        stderr.should.equal(noCoverageError)
-        stdoutShouldEqual(stdout, `
-          ----------|----------|----------|----------|----------|-------------------|
-          File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
-          ----------|----------|----------|----------|----------|-------------------|
-          All files |        0 |      100 |      100 |        0 |                   |
-           index.js |        0 |      100 |      100 |        0 |                 1 |
-          ----------|----------|----------|----------|----------|-------------------|`)
-        next()
-      }
-
-      function executeMainCommand () {
-        const args = [
-          ...globalArgs,
-          '--check-coverage=true',
-          process.execPath, './bin/do-nothing.js'
-        ]
-
-        const proc = spawn(process.execPath, args, spawnOpts)
-
-        var stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', code => checkReport(code, stderr, stdout, executeReport))
-      }
-
-      function executeReport () {
-        const args = [
-          ...globalArgs,
-          '--check-coverage=true',
-          'report'
-        ]
-
-        const proc = spawn(process.execPath, args, spawnOpts)
-
-        var stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', code => checkReport(code, stderr, stdout, executeCheckCoverage))
-      }
-
-      function executeCheckCoverage () {
-        const args = [
-          ...globalArgs,
-          'check-coverage'
-        ]
 
-        const proc = spawn(process.execPath, args, spawnOpts)
-
-        var stderr = ''
-        proc.stderr.on('data', function (chunk) {
-          stderr += chunk
-        })
-
-        var stdout = ''
-        proc.stdout.on('data', function (chunk) {
-          stdout += chunk
-        })
-
-        proc.on('close', code => {
-          code.should.equal(1)
-          stderr.should.equal(noCoverageError)
-          stdoutShouldEqual(stdout, '')
-          done()
-        })
-      }
-
-      executeMainCommand()
+    const { NYC_CONFIG } = JSON.parse(stdout)
+    const config = JSON.parse(NYC_CONFIG, (key, value) => {
+      return key === '' || checkOptions.includes(key) ? value : undefined
     })
 
-    it('instrument', done => {
-      const args = [
-        ...globalArgs,
-        'instrument',
-        'node_modules'
-      ]
-
-      const proc = spawn(process.execPath, args, spawnOpts)
-
-      var stderr = ''
-      proc.stderr.on('data', function (chunk) {
-        stderr += chunk
-      })
-
-      var stdout = ''
-      proc.stdout.on('data', function (chunk) {
-        stdout += chunk
-      })
-
-      proc.on('close', code => {
-        code.should.equal(0)
-        stderr.should.equal('')
-        stdout.should.match(/fake-module-1/)
-        stdout.should.not.match(/fake-module-2/)
-        done()
-      })
-    })
+    t.is(status, 0)
+    t.is(stderr, '')
+    t.matchSnapshot(config)
   })
+})
 
-  it('recursive run does not throw', done => {
-    const args = [
-      bin,
-      process.execPath,
-      bin,
-      process.execPath,
-      bin,
-      process.execPath,
-      bin,
-      'true'
-    ]
-    const proc = spawn(process.execPath, args, {
-      cwd: path.resolve(__dirname, './fixtures/recursive-run')
-    })
-
-    let stdio = ''
-    proc.stderr.on('data', chunk => {
-      stdio += chunk
-    })
-
-    proc.stdout.on('data', chunk => {
-      stdio += chunk
-    })
-
-    proc.on('close', code => {
-      code.should.equal(0)
-      stdio.should.equal('')
-      done()
-    })
+t.test('allows package.json configuration to be overridden with command line args', t => testSuccess(t, {
+  args: ['--reporter=text-lcov', process.execPath, './half-covered.js']
+}))
+
+t.test('loads configuration from package.json and nyc.config.js', t => testSuccess(t, {
+  args: [process.execPath, './index.js'],
+  cwd: nycConfigJS
+}))
+
+t.test('loads configuration from different module rather than nyc.config.js', t => testFailure(t, {
+  args: ['--all', '--nycrc-path', './nycrc-config.js', process.execPath, './index.js'],
+  cwd: nycConfigJS
+}))
+
+t.test('allows nyc.config.js configuration to be overridden with command line args', t => testSuccess(t, {
+  args: ['--all', '--exclude=foo.js', process.execPath, './index.js'],
+  cwd: nycConfigJS
+}))
+
+t.test('loads configuration from package.json and .nycrc', t => testSuccess(t, {
+  args: [process.execPath, './index.js'],
+  cwd: nycrcDir
+}))
+
+t.test('loads configuration from different file rather than .nycrc', t => testFailure(t, {
+  args: ['--nycrc-path', './.nycrc-config.json', process.execPath, './index.js'],
+  cwd: nycrcDir
+}))
+
+t.test('loads configuration from .nycrc.yml', t => testSuccess(t, {
+  args: ['--nycrc-path', './.nycrc.yml', process.execPath, './index.js'],
+  cwd: nycrcDir
+}))
+
+t.test('loads configuration from .nycrc.yaml', t => testSuccess(t, {
+  args: ['--nycrc-path', './.nycrc.yaml', process.execPath, './index.js'],
+  cwd: nycrcDir
+}))
+
+t.test('allows .nycrc configuration to be overridden with command line args', t => testSuccess(t, {
+  args: ['--exclude=foo.js', process.execPath, './index.js'],
+  cwd: nycrcDir
+}))
+
+t.test('reports appropriate coverage information for es6 source files', t => testSuccess(t, {
+  args: ['--reporter=lcov', '--reporter=text', process.execPath, './es6.js']
+}))
+
+t.test('hooks provide coverage for requireJS and AMD modules', t => testSuccess(t, {
+  args: [
+    /* This effectively excludes ./index.js, normalizing results before/after node.js 11.11.0 */
+    '--include=lib/**',
+    '--hook-run-in-this-context',
+    '--hook-require=false',
+    process.execPath,
+    './index.js'
+  ],
+  cwd: path.resolve(__dirname, './fixtures/hooks')
+}))
+
+t.test('does not interpret args intended for instrumented bin', t => {
+  return runNYC({
+    args: ['--silent', process.execPath, 'args.js', '--help', '--version'],
+    leavePathSep: true
+  }).then(({ status, stderr, stdout }) => {
+    t.is(status, 0)
+    t.is(stderr, '')
+    t.matchSnapshot(JSON.parse(stdout).slice(2))
   })
 })
 
-function stdoutShouldEqual (stdout, expected) {
-  `\n${stdout}`.should.equal(`${si(expected)}\n`)
-}
+t.test('interprets first args after -- as Node.js execArgv', t => testSuccess(t, {
+  args: ['--', '--expose-gc', path.resolve(fixturesCLI, 'gc.js')]
+}))
+
+t.test('--show-process-tree displays a tree of spawned processes', t => testSuccess(t, {
+  args: ['--show-process-tree', process.execPath, 'selfspawn-fibonacci.js', '5']
+}))