diff --git a/docs/instrument.md b/docs/instrument.md
index 06126b992..f0a6d3bf8 100644
--- a/docs/instrument.md
+++ b/docs/instrument.md
@@ -18,6 +18,9 @@ nyc instrument [output]
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 `--baseline` option will save a baseline coverage file to `/baseline/coverage.json`.
+Include this file when reporting to highlight files with no test coverage.
+
The `--delete` option will remove the existing output directory before instrumenting.
The `--in-place` option will allow you to run the instrument command.
diff --git a/index.js b/index.js
index 6d74d0831..2d7b31ef2 100755
--- a/index.js
+++ b/index.js
@@ -48,6 +48,7 @@ class NYC {
this.subprocessBin = config.subprocessBin || path.resolve(__dirname, './bin/nyc.js')
this._tempDirectory = config.tempDirectory || config.tempDir || './.nyc_output'
+ this._baselineDirectoryName = 'baseline'
this._instrumenterLib = require(config.instrumenter || './lib/instrumenters/istanbul')
this._reportDir = config.reportDir || 'coverage'
this._sourceMap = typeof config.sourceMap === 'boolean' ? config.sourceMap : true
@@ -170,7 +171,7 @@ class NYC {
return source
}
- async addAllFiles () {
+ async addAllFiles (coverageFilename) {
this._loadAdditionalModules()
this.fakeRequire = true
@@ -190,7 +191,7 @@ class NYC {
})
this.fakeRequire = false
- this.writeCoverageFile()
+ this.writeCoverageFile(coverageFilename)
}
async instrumentAllFiles (input, output) {
@@ -335,6 +336,10 @@ class NYC {
await mkdirp(this.cacheDirectory)
}
+ if (this.config.baseline) {
+ await mkdirp(this.baselineDirectory())
+ }
+
await mkdirp(this.processInfo.directory)
}
@@ -374,26 +379,25 @@ class NYC {
return this
}
- writeCoverageFile () {
- var coverage = coverageFinder()
+ writeCoverageFile (filename = this.processInfo.uuid) {
+ const coverage = coverageFinder()
// Remove any files that should be excluded but snuck into the coverage
- Object.keys(coverage).forEach(function (absFile) {
+ Object.keys(coverage).forEach(absFile => {
if (!this.exclude.shouldInstrument(absFile)) {
delete coverage[absFile]
}
- }, this)
+ })
if (this.cache) {
- Object.keys(coverage).forEach(function (absFile) {
+ Object.keys(coverage).forEach(absFile => {
if (this.hashCache[absFile] && coverage[absFile]) {
coverage[absFile].contentHash = this.hashCache[absFile]
}
- }, this)
+ })
}
- var id = this.processInfo.uuid
- var coverageFilename = path.resolve(this.tempDirectory(), id + '.json')
+ const coverageFilename = path.resolve(this.tempDirectory(), `${filename}.json`)
fs.writeFileSync(
coverageFilename,
@@ -516,6 +520,10 @@ class NYC {
return path.resolve(this.cwd, this._tempDirectory)
}
+ baselineDirectory () {
+ return path.resolve(this.cwd, this._tempDirectory, this._baselineDirectoryName)
+ }
+
reportDirectory () {
return path.resolve(this.cwd, this._reportDir)
}
diff --git a/lib/commands/instrument.js b/lib/commands/instrument.js
index cabb43775..944b0c658 100644
--- a/lib/commands/instrument.js
+++ b/lib/commands/instrument.js
@@ -59,5 +59,14 @@ exports.handler = cliWrapper(async argv => {
})
}
+ if (argv.baseline) {
+ if (argv.clean) {
+ await nyc.reset()
+ } else {
+ await nyc.createTempDirectory()
+ }
+ await nyc.addAllFiles('baseline/coverage')
+ }
+
await nyc.instrumentAllFiles(argv.input, argv.output)
})
diff --git a/test/instrument.js b/test/instrument.js
index 284c2f1cb..2d02d509b 100644
--- a/test/instrument.js
+++ b/test/instrument.js
@@ -353,3 +353,52 @@ t.test('aborts if trying to clean outside working directory', async t => {
t.strictEqual(status, 1)
t.match(stderr, /attempt to delete/)
})
+
+t.test('can produce baseline coverage if `--baseline` is set', async t => {
+ const { status } = await runNYC({
+ args: [
+ 'instrument',
+ '--baseline',
+ './input-dir',
+ './output-dir'
+ ],
+ cwd: subdir
+ })
+
+ t.strictEqual(status, 0)
+ const target = path.resolve(subdir, 'output-dir', 'index.js')
+ t.match(await fs.readFile(target, 'utf8'), /console.log\('Hello, World!'\)/)
+ const baseline = path.resolve(fixturesCLI, '.nyc_output', 'baseline', 'coverage.json')
+ t.match(await fs.readFile(baseline, 'utf8'), /statementMap/)
+})
+
+t.test('can skip cleaning if `--no-clean` is set during baseline', async t => {
+ const args = [
+ 'instrument',
+ '--baseline',
+ './input-dir',
+ './output-dir'
+ ]
+ const cwd = subdir
+
+ const { status: cleanStatus } = await runNYC({ args, cwd })
+
+ t.strictEqual(cleanStatus, 0)
+ const target = path.resolve(subdir, 'output-dir', 'index.js')
+ t.match(await fs.readFile(target, 'utf8'), /console.log\('Hello, World!'\)/)
+ const baseline = path.resolve(fixturesCLI, '.nyc_output', 'baseline', 'coverage.json')
+ t.match(await fs.readFile(baseline, 'utf8'), /statementMap/)
+
+ args.splice(2, 0, '--no-clean')
+ const { status: noCleanStatus } = await runNYC({ args, cwd })
+
+ t.strictEqual(noCleanStatus, 0)
+
+ const baselineDir = path.resolve(fixturesCLI, '.nyc_output', 'baseline')
+ const processinfoDir = path.resolve(fixturesCLI, '.nyc_output', 'processinfo')
+
+ const baselineFiles = await fs.readdir(baselineDir)
+ const processinfoFiles = await fs.readdir(processinfoDir)
+ t.equal(baselineFiles.length, 1)
+ t.equal(processinfoFiles.length, 2)
+})