diff --git a/index.d.ts b/index.d.ts index 04f3be6f9..9ce05a401 100644 --- a/index.d.ts +++ b/index.d.ts @@ -17,7 +17,8 @@ export declare class Report { wrapperLength?: number, resolve?: string, all?: boolean, + src?: Array, + allowExternal: boolean }) - run(): Promise; -} \ No newline at end of file +} diff --git a/lib/report.js b/lib/report.js index 50ba9528e..c8593126d 100644 --- a/lib/report.js +++ b/lib/report.js @@ -21,7 +21,9 @@ class Report { omitRelative, wrapperLength, resolve: resolvePaths, - all + all, + src, + allowExternal = false }) { this.reporter = reporter this.reportsDirectory = reportsDirectory @@ -30,13 +32,24 @@ class Report { this.resolve = resolvePaths this.exclude = new Exclude({ exclude: exclude, - include: include + include: include, + relativePath: !allowExternal }) this.omitRelative = omitRelative this.sourceMapCache = {} this.wrapperLength = wrapperLength this.all = all - this.src = process.cwd() + this.src = this._getSrc(src) + } + + _getSrc (src) { + if (typeof src === 'string') { + return [src] + } else if (Array.isArray(src)) { + return src + } else { + return [process.cwd()] + } } async run () { @@ -159,33 +172,35 @@ class Report { v8ProcessCovs.unshift({ result: emptyReports }) - const workingDir = process.cwd() - this.exclude.globSync(workingDir).forEach((f) => { - const fullPath = resolve(workingDir, f) - if (!fileIndex.has(fullPath)) { - const ext = extname(f) - if (ext === '.js' || ext === '.ts' || ext === '.mjs') { - const stat = statSync(f) - const sourceMap = getSourceMapFromFile(f) - if (sourceMap !== undefined) { - this.sourceMapCache[`file://${fullPath}`] = { data: JSON.parse(readFileSync(sourceMap).toString()) } + const workingDirs = this.src + for (const workingDir of workingDirs) { + this.exclude.globSync(workingDir).forEach((f) => { + const fullPath = resolve(workingDir, f) + if (!fileIndex.has(fullPath)) { + const ext = extname(fullPath) + if (ext === '.js' || ext === '.ts' || ext === '.mjs') { + const stat = statSync(fullPath) + const sourceMap = getSourceMapFromFile(fullPath) + if (sourceMap !== undefined) { + this.sourceMapCache[`file://${fullPath}`] = { data: JSON.parse(readFileSync(sourceMap).toString()) } + } + emptyReports.push({ + scriptId: 0, + url: resolve(fullPath), + functions: [{ + functionName: '(empty-report)', + ranges: [{ + startOffset: 0, + endOffset: stat.size, + count: 0 + }], + isBlockCoverage: true + }] + }) } - emptyReports.push({ - scriptId: 0, - url: resolve(f), - functions: [{ - functionName: '(empty-report)', - ranges: [{ - startOffset: 0, - endOffset: stat.size, - count: 0 - }], - isBlockCoverage: true - }] - }) } - } - }) + }) + } } return mergeProcessCovs(v8ProcessCovs) diff --git a/lib/source-map-from-file.js b/lib/source-map-from-file.js index 8bc971144..1911e11f7 100644 --- a/lib/source-map-from-file.js +++ b/lib/source-map-from-file.js @@ -14,10 +14,10 @@ function getSourceMapFromFile (file) { if (results !== null) { const sourceMap = results[results.length - 1].split('=')[1] if (isAbsolute(sourceMap)) { - return sourceMap + return sourceMap.trim() } else { const base = dirname(file) - return join(base, sourceMap) + return join(base, sourceMap).trim() } } } diff --git a/test/fixtures/multidir1/file1.js b/test/fixtures/multidir1/file1.js new file mode 100644 index 000000000..1ac74b421 --- /dev/null +++ b/test/fixtures/multidir1/file1.js @@ -0,0 +1 @@ +console.log("hi") diff --git a/test/fixtures/multidir2/file2.js b/test/fixtures/multidir2/file2.js new file mode 100644 index 000000000..1ac74b421 --- /dev/null +++ b/test/fixtures/multidir2/file2.js @@ -0,0 +1 @@ +console.log("hi") diff --git a/test/fixtures/report/report-multi-dir-external.js b/test/fixtures/report/report-multi-dir-external.js new file mode 100644 index 000000000..b3ecbb94e --- /dev/null +++ b/test/fixtures/report/report-multi-dir-external.js @@ -0,0 +1,12 @@ +const Report = require('../../../lib/report') +const report = new Report({ + include: ['**/*.js'], + exclude: [], + reporter: ['text'], + tempDirectory: './temp', + omitRelative: true, + all: true, + src: ['../multidir1/', '../multidir2/'], + allowExternal: true +}) +report.run() diff --git a/test/fixtures/report/report-single-dir-external.js b/test/fixtures/report/report-single-dir-external.js new file mode 100644 index 000000000..7ed87f8b1 --- /dev/null +++ b/test/fixtures/report/report-single-dir-external.js @@ -0,0 +1,12 @@ +const Report = require('../../../lib/report') +const report = new Report({ + include: ['**/*.js'], + exclude: [], + reporter: ['text'], + tempDirectory: './temp', + omitRelative: true, + all: true, + src: '../multidir1/', + allowExternal: true +}) +report.run() diff --git a/test/fixtures/report/temp/coverage.json b/test/fixtures/report/temp/coverage.json new file mode 100644 index 000000000..9632d156a --- /dev/null +++ b/test/fixtures/report/temp/coverage.json @@ -0,0 +1 @@ +{"result":[]} \ No newline at end of file diff --git a/test/fixtures/source-maps/padded.js b/test/fixtures/source-maps/padded.js new file mode 100644 index 000000000..05c8cceb3 --- /dev/null +++ b/test/fixtures/source-maps/padded.js @@ -0,0 +1,10 @@ +"use strict"; +exports.__esModule = true; +var loaded_1 = require("./loaded"); +console.log(loaded_1["default"](0)); +console.log(loaded_1["default"](1)); +console.log(loaded_1["default"](-1)); +//# sourceMappingURL=padded.js.map + + +//ew extra whitespace ^ diff --git a/test/integration.js b/test/integration.js index 839766e0e..31f1ec967 100644 --- a/test/integration.js +++ b/test/integration.js @@ -2,6 +2,7 @@ const { spawnSync } = require('child_process') const { statSync } = require('fs') +const { dirname } = require('path') const c8Path = require.resolve('../bin/c8') const nodePath = process.execPath const tsNodePath = './node_modules/.bin/ts-node' @@ -416,4 +417,28 @@ describe('c8', () => { output.toString('utf8').should.matchSnapshot() }) }) + + describe('report', () => { + it('supports reporting on directories outside cwd', () => { + // invoke a script that uses report as an api and supplies src dirs out + // of cwd + const { output } = spawnSync(nodePath, [ + require.resolve('./fixtures/report/report-multi-dir-external.js') + ], { + cwd: dirname(require.resolve('./fixtures/report/report-multi-dir-external.js')) + }) + output.toString('utf8').should.matchSnapshot() + }) + + it('supports reporting on single directories outside cwd', () => { + // invoke a script that uses report as an api and supplies src dirs out + // of cwd + const { output } = spawnSync(nodePath, [ + require.resolve('./fixtures/report/report-single-dir-external.js') + ], { + cwd: dirname(require.resolve('./fixtures/report/report-single-dir-external.js')) + }) + output.toString('utf8').should.matchSnapshot() + }) + }) }) diff --git a/test/integration.js.snap b/test/integration.js.snap index f6936beef..572a8809d 100644 --- a/test/integration.js.snap +++ b/test/integration.js.snap @@ -172,6 +172,29 @@ All files | 83.33 | 85.71 | 60 | 83.33 | " `; +exports[`c8 report supports reporting on directories outside cwd 1`] = ` +",-----------|---------|----------|---------|---------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +-----------|---------|----------|---------|---------|------------------- +All files | 0 | 0 | 0 | 0 | + multidir1 | 0 | 0 | 0 | 0 | + file1.js | 0 | 0 | 0 | 0 | 1 + multidir2 | 0 | 0 | 0 | 0 | + file2.js | 0 | 0 | 0 | 0 | 1 +-----------|---------|----------|---------|---------|------------------- +," +`; + +exports[`c8 report supports reporting on single directories outside cwd 1`] = ` +",----------|---------|----------|---------|---------|------------------- +File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s +----------|---------|----------|---------|---------|------------------- +All files | 0 | 0 | 0 | 0 | + file1.js | 0 | 0 | 0 | 0 | 1 +----------|---------|----------|---------|---------|------------------- +," +`; + exports[`c8 reports coverage for script that exits normally 1`] = ` ",hey i am a line of code diff --git a/test/source-map-from-file.js b/test/source-map-from-file.js new file mode 100644 index 000000000..172cd3167 --- /dev/null +++ b/test/source-map-from-file.js @@ -0,0 +1,14 @@ +/* global describe, it */ +const getSourceMapFromFile = require('../lib/source-map-from-file') +const assert = require('assert') +const path = require('path') +describe('source-map-from-file', () => { + it('should parse source maps from compiled targets', () => { + const sourceMap = getSourceMapFromFile('./test/fixtures/all/ts-compiled/main.js') + assert.strictEqual(sourceMap, ['test', 'fixtures', 'all', 'ts-compiled', 'main.js.map'].join(path.sep)) + }) + it('should handle extra whitespace characters', () => { + const sourceMap = getSourceMapFromFile('./test/fixtures/source-maps/padded.js') + assert.strictEqual(sourceMap, ['test', 'fixtures', 'source-maps', 'padded.js.map'].join(path.sep)) + }) +})