Repository: istanbuljs/nyc
Pull request #1077 (2019-04-19 00:39:11)

 feat: Add support for env.NYC_CONFIG_OVERRIDE 
This allows a process to spawn a child process with an environment
variable NYC_CONFIG_OVERRIDE.  This is a JSON string which overrides any
values in the NYC_CONFIG env.  It is not deleted in the child process,
so will be contagious unless unset, and it is the responsibility of the
caller to manage.

The first intended use case of this feature is to allow node-tap to map
tests to the specific portion of a system under test that they cover.
In this way, unit tests can be more focused, and only re-run when their
specific unit has changed.

There are, of course, many other uses that this could be put to, and it
did not seem appropriate to add a special hook _just_ for overriding
the include list.


coreyfarrell: I'm concerned about our expanding environmental variable surface.  Not specifically against this but I'd like to hear what @JaKXz and @bcoe have to say / if they can think of any alternative methods of accomplishing the goal.
isaacs: @coreyfarrell #1078 removes some environs that are no longer load-bearing, if you're concerned about that.
coreyfarrell: @isaacs I think removing unused environs in the next major release will be good but my concern is more about adding environmental variables which can be set from outside NYC to manipulate how it runs.

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/bin/wrap.js b/bin/wrap.js
index 1cff275..4e64c2b 100644
--- a/bin/wrap.js
+++ b/bin/wrap.js
@@ -16,6 +16,12 @@ if (process.env.NYC_PROCESSINFO_EXTERNAL_ID) {
   delete process.env.NYC_PROCESSINFO_EXTERNAL_ID
 }
 
+if (process.env.NYC_CONFIG_OVERRIDE) {
+  var override = JSON.parse(process.env.NYC_CONFIG_OVERRIDE)
+  config = Object.assign(config, override)
+  process.env.NYC_CONFIG = JSON.stringify(config)
+}
+
 ;(new NYC(config)).wrap()
 
 sw.runMain()
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..9098d2d 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",
@@ -2944,1115 +2969,113 @@
       "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
     },
     "nyc": {
-      "version": "13.3.0",
-      "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.3.0.tgz",
-      "integrity": "sha512-P+FwIuro2aFG6B0Esd9ZDWUd51uZrAEoGutqZxzrVmYl3qSfkLgcQpBPBjtDFsUQLFY1dvTQJPOyeqr8S9GF8w==",
+      "version": "14.0.0",
+      "resolved": "https://registry.npmjs.org/nyc/-/nyc-14.0.0.tgz",
+      "integrity": "sha512-R1zC6UZak6pzn5BZQorkSH5GdOGafrwyeja+eimS5Tu+KJ/hCgBc8qA1QWSzxQmT2FDl2lbpqPw7tBDbSvhAHg==",
       "dev": true,
       "requires": {
         "archy": "^1.0.0",
-        "arrify": "^1.0.1",
-        "caching-transform": "^3.0.1",
+        "caching-transform": "^3.0.2",
         "convert-source-map": "^1.6.0",
-        "find-cache-dir": "^2.0.0",
+        "cp-file": "^6.2.0",
+        "find-cache-dir": "^2.1.0",
         "find-up": "^3.0.0",
         "foreground-child": "^1.5.6",
         "glob": "^7.1.3",
-        "istanbul-lib-coverage": "^2.0.3",
-        "istanbul-lib-hook": "^2.0.3",
-        "istanbul-lib-instrument": "^3.1.0",
-        "istanbul-lib-report": "^2.0.4",
-        "istanbul-lib-source-maps": "^3.0.2",
-        "istanbul-reports": "^2.1.1",
-        "make-dir": "^1.3.0",
+        "istanbul-lib-coverage": "^2.0.4",
+        "istanbul-lib-hook": "^2.0.6",
+        "istanbul-lib-instrument": "^3.2.0",
+        "istanbul-lib-report": "^2.0.7",
+        "istanbul-lib-source-maps": "^3.0.5",
+        "istanbul-reports": "^2.2.2",
+        "make-dir": "^2.1.0",
         "merge-source-map": "^1.1.0",
         "resolve-from": "^4.0.0",
         "rimraf": "^2.6.3",
         "signal-exit": "^3.0.2",
         "spawn-wrap": "^1.4.2",
-        "test-exclude": "^5.1.0",
+        "test-exclude": "^5.2.2",
         "uuid": "^3.3.2",
-        "yargs": "^12.0.5",
-        "yargs-parser": "^11.1.1"
+        "yargs": "^13.2.2",
+        "yargs-parser": "^13.0.0"
+      }
+    },
+    "oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true
+    },
+    "object-keys": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
+      "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==",
+      "dev": true
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "onetime": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+      "dev": true,
+      "requires": {
+        "mimic-fn": "^1.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "append-transform": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "default-require-extensions": "^2.0.0"
-          }
-        },
-        "archy": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "arrify": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "async": {
-          "version": "2.6.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "lodash": "^4.17.11"
-          }
-        },
-        "balanced-match": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "brace-expansion": {
-          "version": "1.1.11",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "balanced-match": "^1.0.0",
-            "concat-map": "0.0.1"
-          }
-        },
-        "caching-transform": {
-          "version": "3.0.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "hasha": "^3.0.0",
-            "make-dir": "^1.3.0",
-            "package-hash": "^3.0.0",
-            "write-file-atomic": "^2.3.0"
-          }
-        },
-        "camelcase": {
-          "version": "5.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "cliui": {
-          "version": "4.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "string-width": "^2.1.1",
-            "strip-ansi": "^4.0.0",
-            "wrap-ansi": "^2.0.0"
-          }
-        },
-        "code-point-at": {
-          "version": "1.1.0",
-          "bundled": true,
-          "dev": true
-        },
-        "commander": {
-          "version": "2.17.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "commondir": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "concat-map": {
-          "version": "0.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "convert-source-map": {
-          "version": "1.6.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.1"
-          }
-        },
-        "cross-spawn": {
-          "version": "4.0.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "lru-cache": "^4.0.1",
-            "which": "^1.2.9"
-          }
-        },
-        "debug": {
-          "version": "4.1.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "decamelize": {
+        "mimic-fn": {
           "version": "1.2.0",
-          "bundled": true,
-          "dev": true
-        },
-        "default-require-extensions": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "strip-bom": "^3.0.0"
-          }
-        },
-        "end-of-stream": {
-          "version": "1.4.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "once": "^1.4.0"
-          }
-        },
-        "error-ex": {
-          "version": "1.3.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "is-arrayish": "^0.2.1"
-          }
-        },
-        "es6-error": {
-          "version": "4.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+          "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
           "dev": true
-        },
-        "execa": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^6.0.0",
-            "get-stream": "^4.0.0",
-            "is-stream": "^1.1.0",
-            "npm-run-path": "^2.0.0",
-            "p-finally": "^1.0.0",
-            "signal-exit": "^3.0.0",
-            "strip-eof": "^1.0.0"
-          },
-          "dependencies": {
-            "cross-spawn": {
-              "version": "6.0.5",
-              "bundled": true,
-              "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"
-              }
-            }
-          }
-        },
-        "find-cache-dir": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "commondir": "^1.0.1",
-            "make-dir": "^1.0.0",
-            "pkg-dir": "^3.0.0"
-          }
-        },
-        "find-up": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "foreground-child": {
-          "version": "1.5.6",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^4",
-            "signal-exit": "^3.0.0"
-          }
-        },
-        "fs.realpath": {
+        }
+      }
+    },
+    "opener": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
+      "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
+      "dev": true
+    },
+    "optimist": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
+      "requires": {
+        "minimist": "~0.0.1",
+        "wordwrap": "~0.0.2"
+      }
+    },
+    "optionator": {
+      "version": "0.8.2",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+      "dev": true,
+      "requires": {
+        "deep-is": "~0.1.3",
+        "fast-levenshtein": "~2.0.4",
+        "levn": "~0.3.0",
+        "prelude-ls": "~1.1.2",
+        "type-check": "~0.3.2",
+        "wordwrap": "~1.0.0"
+      },
+      "dependencies": {
+        "wordwrap": {
           "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "get-caller-file": {
-          "version": "1.0.3",
-          "bundled": true,
-          "dev": true
-        },
-        "get-stream": {
-          "version": "4.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "pump": "^3.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.3",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "graceful-fs": {
-          "version": "4.1.15",
-          "bundled": true,
-          "dev": true
-        },
-        "handlebars": {
-          "version": "4.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "async": "^2.5.0",
-            "optimist": "^0.6.1",
-            "source-map": "^0.6.1",
-            "uglify-js": "^3.1.4"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.6.1",
-              "bundled": true,
-              "dev": true
-            }
-          }
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "hasha": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "is-stream": "^1.0.1"
-          }
-        },
-        "hosted-git-info": {
-          "version": "2.7.1",
-          "bundled": true,
-          "dev": true
-        },
-        "imurmurhash": {
-          "version": "0.1.4",
-          "bundled": true,
-          "dev": true
-        },
-        "inflight": {
-          "version": "1.0.6",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "once": "^1.3.0",
-            "wrappy": "1"
-          }
-        },
-        "inherits": {
-          "version": "2.0.3",
-          "bundled": true,
-          "dev": true
-        },
-        "invert-kv": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "is-arrayish": {
-          "version": "0.2.1",
-          "bundled": true,
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "is-stream": {
-          "version": "1.1.0",
-          "bundled": true,
-          "dev": true
-        },
-        "isexe": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "istanbul-lib-coverage": {
-          "version": "2.0.3",
-          "bundled": true,
-          "dev": true
-        },
-        "istanbul-lib-hook": {
-          "version": "2.0.3",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "append-transform": "^1.0.0"
-          }
-        },
-        "istanbul-lib-report": {
-          "version": "2.0.4",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "istanbul-lib-coverage": "^2.0.3",
-            "make-dir": "^1.3.0",
-            "supports-color": "^6.0.0"
-          },
-          "dependencies": {
-            "supports-color": {
-              "version": "6.1.0",
-              "bundled": true,
-              "dev": true,
-              "requires": {
-                "has-flag": "^3.0.0"
-              }
-            }
-          }
-        },
-        "istanbul-lib-source-maps": {
-          "version": "3.0.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "debug": "^4.1.1",
-            "istanbul-lib-coverage": "^2.0.3",
-            "make-dir": "^1.3.0",
-            "rimraf": "^2.6.2",
-            "source-map": "^0.6.1"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.6.1",
-              "bundled": true,
-              "dev": true
-            }
-          }
-        },
-        "istanbul-reports": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "handlebars": "^4.1.0"
-          }
-        },
-        "json-parse-better-errors": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true
-        },
-        "lcid": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "invert-kv": "^2.0.0"
-          }
-        },
-        "load-json-file": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^4.0.0",
-            "pify": "^3.0.0",
-            "strip-bom": "^3.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "lodash": {
-          "version": "4.17.11",
-          "bundled": true,
-          "dev": true
-        },
-        "lodash.flattendeep": {
-          "version": "4.4.0",
-          "bundled": true,
-          "dev": true
-        },
-        "lru-cache": {
-          "version": "4.1.5",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "pseudomap": "^1.0.2",
-            "yallist": "^2.1.2"
-          }
-        },
-        "make-dir": {
-          "version": "1.3.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "pify": "^3.0.0"
-          }
-        },
-        "map-age-cleaner": {
-          "version": "0.1.3",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "p-defer": "^1.0.0"
-          }
-        },
-        "mem": {
-          "version": "4.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "map-age-cleaner": "^0.1.1",
-            "mimic-fn": "^1.0.0",
-            "p-is-promise": "^2.0.0"
-          }
-        },
-        "merge-source-map": {
-          "version": "1.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "source-map": "^0.6.1"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.6.1",
-              "bundled": true,
-              "dev": true
-            }
-          }
-        },
-        "mimic-fn": {
-          "version": "1.2.0",
-          "bundled": true,
-          "dev": true
-        },
-        "minimatch": {
-          "version": "3.0.4",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
-        "minimist": {
-          "version": "0.0.10",
-          "bundled": true,
-          "dev": true
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.8"
-          },
-          "dependencies": {
-            "minimist": {
-              "version": "0.0.8",
-              "bundled": true,
-              "dev": true
-            }
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true
-        },
-        "nice-try": {
-          "version": "1.0.5",
-          "bundled": true,
-          "dev": true
-        },
-        "normalize-package-data": {
-          "version": "2.5.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "hosted-git-info": "^2.1.4",
-            "resolve": "^1.10.0",
-            "semver": "2 || 3 || 4 || 5",
-            "validate-npm-package-license": "^3.0.1"
-          }
-        },
-        "npm-run-path": {
-          "version": "2.0.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "path-key": "^2.0.0"
-          }
-        },
-        "number-is-nan": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "once": {
-          "version": "1.4.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "wrappy": "1"
-          }
-        },
-        "optimist": {
-          "version": "0.6.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "minimist": "~0.0.1",
-            "wordwrap": "~0.0.2"
-          }
-        },
-        "os-homedir": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true
-        },
-        "os-locale": {
-          "version": "3.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "execa": "^1.0.0",
-            "lcid": "^2.0.0",
-            "mem": "^4.0.0"
-          }
-        },
-        "p-defer": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "p-finally": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "p-is-promise": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "p-limit": {
-          "version": "2.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "p-try": "^2.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "p-try": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "package-hash": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.15",
-            "hasha": "^3.0.0",
-            "lodash.flattendeep": "^4.4.0",
-            "release-zalgo": "^1.0.0"
-          }
-        },
-        "parse-json": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "path-is-absolute": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "path-key": {
-          "version": "2.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "path-parse": {
-          "version": "1.0.6",
-          "bundled": true,
-          "dev": true
-        },
-        "path-type": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "pify": "^3.0.0"
-          }
-        },
-        "pify": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "pkg-dir": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "find-up": "^3.0.0"
-          }
-        },
-        "pseudomap": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true
-        },
-        "pump": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        },
-        "read-pkg": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "load-json-file": "^4.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^3.0.0"
-          }
-        },
-        "read-pkg-up": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "find-up": "^3.0.0",
-            "read-pkg": "^3.0.0"
-          }
-        },
-        "release-zalgo": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "es6-error": "^4.0.1"
-          }
-        },
-        "require-directory": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true
-        },
-        "require-main-filename": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true
-        },
-        "resolve": {
-          "version": "1.10.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "path-parse": "^1.0.6"
-          }
-        },
-        "resolve-from": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "rimraf": {
-          "version": "2.6.3",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.1.2",
-          "bundled": true,
-          "dev": true
-        },
-        "semver": {
-          "version": "5.6.0",
-          "bundled": true,
-          "dev": true
-        },
-        "set-blocking": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "shebang-command": {
-          "version": "1.2.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "shebang-regex": "^1.0.0"
-          }
-        },
-        "shebang-regex": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "signal-exit": {
-          "version": "3.0.2",
-          "bundled": true,
-          "dev": true
-        },
-        "spawn-wrap": {
-          "version": "1.4.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "foreground-child": "^1.5.6",
-            "mkdirp": "^0.5.0",
-            "os-homedir": "^1.0.1",
-            "rimraf": "^2.6.2",
-            "signal-exit": "^3.0.2",
-            "which": "^1.3.0"
-          }
-        },
-        "spdx-correct": {
-          "version": "3.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "spdx-expression-parse": "^3.0.0",
-            "spdx-license-ids": "^3.0.0"
-          }
-        },
-        "spdx-exceptions": {
-          "version": "2.2.0",
-          "bundled": true,
-          "dev": true
-        },
-        "spdx-expression-parse": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "spdx-exceptions": "^2.1.0",
-            "spdx-license-ids": "^3.0.0"
-          }
-        },
-        "spdx-license-ids": {
-          "version": "3.0.3",
-          "bundled": true,
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
-          }
-        },
-        "strip-bom": {
-          "version": "3.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "strip-eof": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "test-exclude": {
-          "version": "5.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "arrify": "^1.0.1",
-            "minimatch": "^3.0.4",
-            "read-pkg-up": "^4.0.0",
-            "require-main-filename": "^1.0.1"
-          }
-        },
-        "uglify-js": {
-          "version": "3.4.9",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "commander": "~2.17.1",
-            "source-map": "~0.6.1"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.6.1",
-              "bundled": true,
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
-        "uuid": {
-          "version": "3.3.2",
-          "bundled": true,
-          "dev": true
-        },
-        "validate-npm-package-license": {
-          "version": "3.0.4",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "spdx-correct": "^3.0.0",
-            "spdx-expression-parse": "^3.0.0"
-          }
-        },
-        "which": {
-          "version": "1.3.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "isexe": "^2.0.0"
-          }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "wordwrap": {
-          "version": "0.0.3",
-          "bundled": true,
-          "dev": true
-        },
-        "wrap-ansi": {
-          "version": "2.1.0",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1"
-          },
-          "dependencies": {
-            "ansi-regex": {
-              "version": "2.1.1",
-              "bundled": true,
-              "dev": true
-            },
-            "is-fullwidth-code-point": {
-              "version": "1.0.0",
-              "bundled": true,
-              "dev": true,
-              "requires": {
-                "number-is-nan": "^1.0.0"
-              }
-            },
-            "string-width": {
-              "version": "1.0.2",
-              "bundled": true,
-              "dev": true,
-              "requires": {
-                "code-point-at": "^1.0.0",
-                "is-fullwidth-code-point": "^1.0.0",
-                "strip-ansi": "^3.0.0"
-              }
-            },
-            "strip-ansi": {
-              "version": "3.0.1",
-              "bundled": true,
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^2.0.0"
-              }
-            }
-          }
-        },
-        "wrappy": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true
-        },
-        "write-file-atomic": {
-          "version": "2.4.2",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.11",
-            "imurmurhash": "^0.1.4",
-            "signal-exit": "^3.0.2"
-          }
-        },
-        "y18n": {
-          "version": "4.0.0",
-          "bundled": true,
-          "dev": true
-        },
-        "yallist": {
-          "version": "2.1.2",
-          "bundled": true,
-          "dev": true
-        },
-        "yargs": {
-          "version": "12.0.5",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "cliui": "^4.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^3.0.0",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^2.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^3.2.1 || ^4.0.0",
-            "yargs-parser": "^11.1.1"
-          }
-        },
-        "yargs-parser": {
-          "version": "11.1.1",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
-        }
-      }
-    },
-    "oauth-sign": {
-      "version": "0.9.0",
-      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
-      "dev": true
-    },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
-    },
-    "object-keys": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
-      "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==",
-      "dev": true
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "onetime": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
-      "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
-      "dev": true,
-      "requires": {
-        "mimic-fn": "^1.0.0"
-      },
-      "dependencies": {
-        "mimic-fn": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
-          "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
-          "dev": true
-        }
-      }
-    },
-    "opener": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
-      "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
-      "dev": true
-    },
-    "optimist": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-      "requires": {
-        "minimist": "~0.0.1",
-        "wordwrap": "~0.0.2"
-      }
-    },
-    "optionator": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
-      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
-      "dev": true,
-      "requires": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.4",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "wordwrap": "~1.0.0"
-      },
-      "dependencies": {
-        "wordwrap": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-          "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+          "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
           "dev": true
         }
       }
@@ -4960,9 +3983,9 @@
       }
     },
     "tap": {
-      "version": "12.6.1",
-      "resolved": "https://registry.npmjs.org/tap/-/tap-12.6.1.tgz",
-      "integrity": "sha512-av4rQscF4IspCJ16BM+/G6LKcKwkB6HBtixf0x0PTZQCW3KlicBy9F4SwkazbMSGMrecVWvFQFeabiy5YPhAhw==",
+      "version": "12.6.2",
+      "resolved": "https://registry.npmjs.org/tap/-/tap-12.6.2.tgz",
+      "integrity": "sha512-aZzkmzzlmgGjG0GouacDJoeMHz85u7bSGhmPqLCmseM47ealw9KGHI6722lGKcyPu1Kktq7GOUdcy03+etgw8A==",
       "dev": true,
       "requires": {
         "bind-obj-methods": "^2.0.0",
@@ -4978,10 +4001,10 @@
         "function-loop": "^1.0.1",
         "glob": "^7.1.3",
         "isexe": "^2.0.0",
-        "js-yaml": "^3.13.0",
+        "js-yaml": "^3.13.1",
         "minipass": "^2.3.5",
         "mkdirp": "^0.5.1",
-        "nyc": "^13.3.0",
+        "nyc": "^14.0.0",
         "opener": "^1.5.1",
         "os-homedir": "^1.0.2",
         "own-or": "^1.0.0",
@@ -5167,9 +4190,9 @@
       }
     },
     "ts-node": {
-      "version": "8.0.3",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.3.tgz",
-      "integrity": "sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA==",
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.0.tgz",
+      "integrity": "sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A==",
       "dev": true,
       "requires": {
         "arg": "^4.1.0",
@@ -5230,9 +4253,9 @@
       "dev": true
     },
     "typescript": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.1.tgz",
-      "integrity": "sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==",
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz",
+      "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==",
       "dev": true
     },
     "uglify-js": {
@@ -5472,9 +4495,9 @@
       }
     },
     "yn": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz",
-      "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz",
+      "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==",
       "dev": true
     },
     "zero-fill": {
diff --git a/package.json b/package.json
index 372e2c2..b2b6f0a 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 npm test",
+    "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,16 +98,18 @@
     "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",
     "standard": "^12.0.1",
     "standard-version": "^5.0.2",
     "strip-indent": "^2.0.0",
-    "tap": "^12.6.1",
+    "tap": "^12.6.2",
     "which": "^1.3.1",
     "zero-fill": "^2.2.3"
   },


Test patch:
diff --git a/tap-snapshots/test-config-override.js-TAP.test.js b/tap-snapshots/test-config-override.js-TAP.test.js
new file mode 100644
index 0000000..63ff6ff
--- /dev/null
+++ b/tap-snapshots/test-config-override.js-TAP.test.js
@@ -0,0 +1,20 @@
+/* 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/config-override.js TAP spawn that does config overriding > stdout 1`] = `
+in parent { include: 'conf-override-root.js' }
+in child { include: 'conf-override-module.js' }
+in module { include: 'conf-override-module.js' }
+-------------------------|----------|----------|----------|----------|-------------------|
+File                     |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
+-------------------------|----------|----------|----------|----------|-------------------|
+All files                |    77.78 |       50 |      100 |    77.78 |                   |
+ conf-override-module.js |      100 |      100 |      100 |      100 |                   |
+ conf-override-root.js   |    71.43 |       50 |      100 |    71.43 |             22,23 |
+-------------------------|----------|----------|----------|----------|-------------------|
+
+`
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..a53ebec
--- /dev/null
+++ b/tap-snapshots/test-nyc-integration.js-TAP.test.js
@@ -0,0 +1,595 @@
+/* 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`] = `
+[
+  [
+    "cache",
+    false
+  ],
+  [
+    "cacheDir",
+    "/tmp"
+  ],
+  [
+    "exclude",
+    "batman.js"
+  ],
+  [
+    "extension",
+    ".js"
+  ],
+  [
+    "include",
+    "env.js"
+  ],
+  [
+    "instrumenter",
+    "./lib/instrumenters/istanbul"
+  ],
+  [
+    "require",
+    "make-dir"
+  ],
+  [
+    "silent",
+    true
+  ],
+  [
+    "sourceMap",
+    true
+  ]
+]
+`
+
+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/config-override.js b/test/config-override.js
new file mode 100644
index 0000000..c459a87
--- /dev/null
+++ b/test/config-override.js
@@ -0,0 +1,33 @@
+const { spawn } = require('child_process')
+const { resolve } = require('path')
+const t = require('tap')
+const node = process.execPath
+const fixturesCLI = resolve(__dirname, './fixtures/cli')
+const bin = resolve(__dirname, '../self-coverage/bin/nyc')
+const rimraf = require('rimraf').sync
+const tmp = 'conf-override-test'
+
+rimraf(resolve(fixturesCLI, tmp))
+t.teardown(() => rimraf(resolve(fixturesCLI, tmp)))
+
+t.test('spawn that does config overriding', t => {
+  const args = [
+    bin, '-t', tmp,
+    '--exclude-after-remap=false',
+    '--include=conf-override-root.js',
+    node, 'conf-override-root.js'
+  ]
+  const proc = spawn(node, args, {
+    cwd: fixturesCLI
+  })
+  const out = []
+  const err = []
+  proc.stdout.on('data', c => out.push(c))
+  proc.stderr.on('data', c => err.push(c))
+  proc.on('close', (code, signal) => {
+    t.equal(code, 0)
+    t.equal(signal, null)
+    t.matchSnapshot(Buffer.concat(out).toString(), 'stdout')
+    t.end()
+  })
+})
diff --git a/test/fixtures/cli/conf-override-module.js b/test/fixtures/cli/conf-override-module.js
new file mode 100644
index 0000000..d949d34
--- /dev/null
+++ b/test/fixtures/cli/conf-override-module.js
@@ -0,0 +1,2 @@
+const config = JSON.parse(process.env.NYC_CONFIG)
+console.log('in module', {include: config.include})
diff --git a/test/fixtures/cli/conf-override-root.js b/test/fixtures/cli/conf-override-root.js
new file mode 100755
index 0000000..a7a99f6
--- /dev/null
+++ b/test/fixtures/cli/conf-override-root.js
@@ -0,0 +1,24 @@
+const config = JSON.parse(process.env.NYC_CONFIG)
+const { include } = config
+
+if (process.argv[2] !== 'child') {
+  console.log('in parent', { include })
+  require('child_process').spawn(process.execPath, [__filename, 'child'], {
+    cwd: __dirname,
+    env: Object.assign(
+      {},
+      process.env,
+      {
+        NYC_CONFIG_OVERRIDE: JSON.stringify({
+          include: 'conf-override-module.js'
+        })
+      }
+    ),
+    stdio: 'inherit',
+  })
+} else {
+  // this should run, but not be covered, even though the shebang says to
+  // the child run ONLY covers the child file, not the dump-root.js
+  console.log('in child', { include })
+  require('./conf-override-module.js')
+}
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..e0e7ab4 100644
--- a/test/nyc-integration.js
+++ b/test/nyc-integration.js
@@ -1,1978 +1,191 @@
-/* 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']
+if (process.env.TAP_SNAPSHOT !== '1') {
+  t.jobs = os.cpus().length
+}
 
-      var proc = spawn(process.execPath, args, {
-        cwd: fixturesCLI,
-        env: env
-      })
+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('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()
-      })
-    })
-  })
+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('handles --clean / --no-clean properly', () => {
-    rimraf.sync(path.resolve(fixturesCLI, '.nyc_output'))
-    const args = (doClean, arg) => [
-      bin,
-      doClean ? '--clean' : '--no-clean',
+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,
-      './by-arg2.js',
-      arg
+      './env.js'
     ]
-    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'
+  }).then(({ stdout, stderr, status }) => {
+    const checkOptions = [
+      'instrumenter',
+      'silent',
+      'cacheDir',
+      'cache',
+      'sourceMap',
+      'require',
+      'include',
+      'exclude',
+      'extension'
     ]
 
-    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
-        })
+    const config = JSON.parse(JSON.parse(stdout).NYC_CONFIG)
 
-        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()
-      })
-    })
+    t.is(status, 0)
+    t.is(stderr, '')
+    t.matchSnapshot(
+      JSON.stringify(
+        checkOptions.sort().map(option => [option, config[option]]),
+        null,
+        2
+      )
+    )
   })
+})
 
-  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']
+}))