diff --git a/.circleci/config.yml b/.circleci/config.yml index 36f96851..a00aca9c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -354,6 +354,43 @@ workflows: ../../node_modules/.bin/only-covered main.js working_directory: examples/support-files + - cypress/run: + attach-workspace: true + name: example-all-files + requires: + - cypress/install + # there are no jobs to follow this one + # so no need to save the workspace files (saves time) + no-workspace: true + start: npm start --prefix examples/all-files + wait-on: 'http://localhost:1234' + command: npx cypress run --project examples/all-files + # store screenshots and videos + store_artifacts: true + post-steps: + - run: cat examples/all-files/.nyc_output/out.json + - run: cat examples/all-files/coverage/coverage-final.json + # store the created coverage report folder + # you can click on it in the CircleCI UI + # to see live static HTML site + - store_artifacts: + path: examples/all-files/coverage + # make sure the examples captures 100% of code + - run: + command: npx nyc report --check-coverage true --lines 100 + working_directory: examples/all-files + - run: + name: Check code coverage 📈 + # we will check the final coverage report + # to make sure it only has files we are interested in + # because there are files covered at 0 in the report + command: | + ../../node_modules/.bin/check-coverage main.js + ../../node_modules/.bin/check-coverage second.js + ../../node_modules/.bin/check-coverage not-covered.js + ../../node_modules/.bin/only-covered --from coverage/coverage-final.json main.js second.js not-covered.js + working_directory: examples/all-files + - cypress/run: attach-workspace: true name: example-exclude-files @@ -467,3 +504,4 @@ workflows: - example-exclude-files - example-docker-paths - example-use-webpack + - example-all-files diff --git a/README.md b/README.md index 78e8a331..a4bf6016 100644 --- a/README.md +++ b/README.md @@ -298,6 +298,8 @@ For example, if you want to only include files in the `app` folder, but exclude } ``` +**Note:** if you have `all: true` NYC option set, this plugin will check the produced `.nyc_output/out.json` before generating the final report. If the `out.json` file does not have information for some files that should be there according to `include` list, then an empty placeholder will be included, see [PR 208](https://github.com/cypress-io/code-coverage/pull/208). + ## Disable plugin You can skip the client-side code coverage hooks by setting the environment variable `coverage` to `false`. diff --git a/common-utils.js b/common-utils.js new file mode 100644 index 00000000..d2c786a8 --- /dev/null +++ b/common-utils.js @@ -0,0 +1,37 @@ +// @ts-check +function combineNycOptions({ + pkgNycOptions, + nycrc, + nycrcJson, + defaultNycOptions +}) { + // last option wins + const nycOptions = Object.assign( + {}, + defaultNycOptions, + nycrc, + nycrcJson, + pkgNycOptions + ) + + if (typeof nycOptions.reporter === 'string') { + nycOptions.reporter = [nycOptions.reporter] + } + if (typeof nycOptions.extension === 'string') { + nycOptions.extension = [nycOptions.extension] + } + + return nycOptions +} + +const defaultNycOptions = { + 'report-dir': './coverage', + reporter: ['lcov', 'clover', 'json'], + extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'], + excludeAfterRemap: true +} + +module.exports = { + combineNycOptions, + defaultNycOptions +} diff --git a/cypress/integration/combine-spec.js b/cypress/integration/combine-spec.js index 9c05d1a6..1d6718b6 100644 --- a/cypress/integration/combine-spec.js +++ b/cypress/integration/combine-spec.js @@ -1,4 +1,4 @@ -const { combineNycOptions, defaultNycOptions } = require('../../task-utils') +const { combineNycOptions, defaultNycOptions } = require('../../common-utils') describe('Combine NYC options', () => { it('overrides defaults', () => { const pkgNycOptions = { diff --git a/examples/all-files/.babelrc b/examples/all-files/.babelrc new file mode 100644 index 00000000..7a016cf8 --- /dev/null +++ b/examples/all-files/.babelrc @@ -0,0 +1,3 @@ +{ + "plugins": ["istanbul"] +} diff --git a/examples/all-files/README.md b/examples/all-files/README.md new file mode 100644 index 00000000..e5faf288 --- /dev/null +++ b/examples/all-files/README.md @@ -0,0 +1 @@ +# example: all files diff --git a/examples/all-files/cypress.json b/examples/all-files/cypress.json new file mode 100644 index 00000000..5abc6bc7 --- /dev/null +++ b/examples/all-files/cypress.json @@ -0,0 +1,4 @@ +{ + "fixturesFolder": false, + "baseUrl": "http://localhost:1234" +} diff --git a/examples/all-files/cypress/integration/spec.js b/examples/all-files/cypress/integration/spec.js new file mode 100644 index 00000000..d7ca62b2 --- /dev/null +++ b/examples/all-files/cypress/integration/spec.js @@ -0,0 +1,12 @@ +/// +it('works', () => { + cy.visit('/') + cy.contains('Page body') + + cy.window() + .invoke('reverse', 'super') + .should('equal', 'repus') + + // application's code should be instrumented + cy.window().should('have.property', '__coverage__') +}) diff --git a/examples/all-files/cypress/plugins/index.js b/examples/all-files/cypress/plugins/index.js new file mode 100644 index 00000000..b17c48db --- /dev/null +++ b/examples/all-files/cypress/plugins/index.js @@ -0,0 +1,5 @@ +module.exports = (on, config) => { + require('../../../../task')(on, config) + on('file:preprocessor', require('../../../../use-babelrc')) + return config +} diff --git a/examples/all-files/cypress/support/commands.js b/examples/all-files/cypress/support/commands.js new file mode 100644 index 00000000..219920ee --- /dev/null +++ b/examples/all-files/cypress/support/commands.js @@ -0,0 +1,2 @@ +import '../../../../support' +console.log('this is commands file') diff --git a/examples/all-files/cypress/support/index.js b/examples/all-files/cypress/support/index.js new file mode 100644 index 00000000..b5c578c9 --- /dev/null +++ b/examples/all-files/cypress/support/index.js @@ -0,0 +1 @@ +require('./commands') diff --git a/examples/all-files/index.html b/examples/all-files/index.html new file mode 100644 index 00000000..993f0c18 --- /dev/null +++ b/examples/all-files/index.html @@ -0,0 +1,17 @@ + + Page body + + + + diff --git a/examples/all-files/main.js b/examples/all-files/main.js new file mode 100644 index 00000000..5dd69be2 --- /dev/null +++ b/examples/all-files/main.js @@ -0,0 +1,3 @@ +window.add = (a, b) => a + b + +window.sub = (a, b) => a - b diff --git a/examples/all-files/not-covered.js b/examples/all-files/not-covered.js new file mode 100644 index 00000000..39897541 --- /dev/null +++ b/examples/all-files/not-covered.js @@ -0,0 +1,7 @@ +// this file is NOT included from "index.html" +// thus it is not instrumented and not included +// in the final code coverage numbers +function throwsError() { + throw new Error('NO') +} +throwsError() diff --git a/examples/all-files/package.json b/examples/all-files/package.json new file mode 100644 index 00000000..59c6d0a8 --- /dev/null +++ b/examples/all-files/package.json @@ -0,0 +1,19 @@ +{ + "name": "example-all-files", + "description": "Report all files", + "scripts": { + "start": "../../node_modules/.bin/parcel serve index.html", + "cy:open": "../../node_modules/.bin/cypress open", + "cy:run": "../../node_modules/.bin/cypress run", + "dev": "../../node_modules/.bin/start-test 1234 cy:open", + "e2e": "../../node_modules/.bin/start-test 1234 cy:run", + "report": "../../node_modules/.bin/nyc report" + }, + "nyc": { + "all": true, + "include": "*.js" + }, + "devDependencies": { + "@babel/core": "7.9.0" + } +} diff --git a/examples/all-files/second.js b/examples/all-files/second.js new file mode 100644 index 00000000..494a0c5f --- /dev/null +++ b/examples/all-files/second.js @@ -0,0 +1,7 @@ +// this file should be excluded from the final coverage numbers +// using "nyc.exclude" list in package.json +window.reverse = s => + s + .split('') + .reverse() + .join('') diff --git a/package-lock.json b/package-lock.json index 75cd32dc..86d316b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2976,7 +2976,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.3", "run-parallel": "^1.1.9" @@ -2985,8 +2984,7 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" } } }, @@ -3000,7 +2998,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.3", "fastq": "^1.6.0" @@ -4164,8 +4161,7 @@ "array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" }, "array-unique": { "version": "0.3.2", @@ -6742,7 +6738,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "requires": { "path-type": "^4.0.0" }, @@ -6750,8 +6745,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" } } }, @@ -7558,7 +7552,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.7.0.tgz", "integrity": "sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -8497,7 +8490,6 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", - "dev": true, "requires": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -8510,14 +8502,12 @@ "@nodelib/fs.stat": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", - "dev": true + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" }, "braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -8526,7 +8516,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -8540,7 +8529,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -8549,7 +8537,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -8557,20 +8544,17 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "merge2": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", - "dev": true + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.0.5" @@ -8580,7 +8564,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -8983,8 +8966,7 @@ "ignore": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", - "dev": true + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==" }, "import-fresh": { "version": "2.0.0", @@ -15570,8 +15552,7 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { "version": "2.3.0", @@ -16967,8 +16948,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rgb-regex": { "version": "1.0.1", @@ -17003,8 +16983,7 @@ "run-parallel": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", - "dev": true + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" }, "run-queue": { "version": "1.0.3", @@ -17582,8 +17561,7 @@ "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, "slice-ansi": { "version": "0.0.4", diff --git a/package.json b/package.json index 7ffea21b..58ca69c3 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,9 @@ "@cypress/browserify-preprocessor": "2.2.1", "debug": "4.1.1", "execa": "4.0.0", - "nyc": "15.0.1", - "istanbul-lib-coverage": "3.0.0" + "globby": "11.0.0", + "istanbul-lib-coverage": "3.0.0", + "nyc": "15.0.1" }, "devDependencies": { "@babel/core": "7.9.0", diff --git a/task-utils.js b/task-utils.js index 7abd6274..05b729df 100644 --- a/task-utils.js +++ b/task-utils.js @@ -7,38 +7,8 @@ const { readFileSync, writeFileSync, existsSync } = require('fs') const { isAbsolute, resolve, join } = require('path') const debug = require('debug')('code-coverage') const chalk = require('chalk') - -function combineNycOptions({ - pkgNycOptions, - nycrc, - nycrcJson, - defaultNycOptions -}) { - // last option wins - const nycOptions = Object.assign( - {}, - defaultNycOptions, - nycrc, - nycrcJson, - pkgNycOptions - ) - - if (typeof nycOptions.reporter === 'string') { - nycOptions.reporter = [nycOptions.reporter] - } - if (typeof nycOptions.extension === 'string') { - nycOptions.extension = [nycOptions.extension] - } - - return nycOptions -} - -const defaultNycOptions = { - 'report-dir': './coverage', - reporter: ['lcov', 'clover', 'json'], - extension: ['.js', '.cjs', '.mjs', '.ts', '.tsx', '.jsx'], - excludeAfterRemap: true -} +const globby = require('globby') +const { combineNycOptions, defaultNycOptions } = require('./common-utils') function readNycOptions(workingDirectory) { const pkgFilename = join(workingDirectory, 'package.json') @@ -264,12 +234,116 @@ function tryFindingLocalFiles(nycFilename) { } } +/** + * Tries to find source files to be included in the final coverage report + * using NYC options: extension list, include and exclude. + */ +function findSourceFiles(nycOptions) { + debug('include all files options: %o', { + all: nycOptions.all, + include: nycOptions.include, + exclude: nycOptions.exclude, + extension: nycOptions.extension + }) + + if (!Array.isArray(nycOptions.extension)) { + console.error( + 'Expected NYC "extension" option to be a list of file extensions' + ) + console.error(nycOptions) + return [] + } + + let patterns = [] + if (Array.isArray(nycOptions.include)) { + patterns = patterns.concat(nycOptions.include) + } else if (typeof nycOptions.include === 'string') { + patterns.push(nycOptions.include) + } else { + debug('using default list of extensions') + nycOptions.extension.forEach(extension => { + patterns.push('**/*' + extension) + }) + } + + if (Array.isArray(nycOptions.exclude)) { + const negated = nycOptions.exclude.map(s => '!' + s) + patterns = patterns.concat(negated) + } else if (typeof nycOptions.exclude === 'string') { + patterns.push('!' + nycOptions.exclude) + } + // always exclude node_modules + // https://github.com/istanbuljs/nyc#including-files-within-node_modules + patterns.push('!**/node_modules/**') + + debug('searching files to include using patterns %o', patterns) + + const allFiles = globby.sync(patterns, { absolute: true }) + return allFiles +} +/** + * If the website or unit tests did not load ALL files we need to + * include, then we should include the missing files ourselves + * before generating the report. + * + * @see https://github.com/cypress-io/code-coverage/issues/207 + */ +function includeAllFiles(nycFilename, nycOptions) { + if (!nycOptions.all) { + debug('NYC "all" option is not set, skipping including all files') + return + } + + const allFiles = findSourceFiles(nycOptions) + if (debug.enabled) { + debug('found %d file(s)', allFiles.length) + console.error(allFiles.join('\n')) + } + if (!allFiles.length) { + debug('no files found, hoping for the best') + return + } + + const nycCoverage = JSON.parse(readFileSync(nycFilename, 'utf8')) + const coverageKeys = Object.keys(nycCoverage) + const coveredPaths = coverageKeys.map(key => nycCoverage[key].path) + debug('coverage has the following paths %o', coveredPaths) + + let changed + allFiles.forEach(fullPath => { + if (coveredPaths.includes(fullPath)) { + // all good, this file exists in coverage object + return + } + debug('adding empty coverage for file %s', fullPath) + changed = true + // insert placeholder object for now + nycCoverage[fullPath] = { + path: fullPath, + statementMap: {}, + fnMap: {}, + branchMap: {}, + s: {}, + f: {}, + b: {} + } + }) + + if (changed) { + debug('saving updated file %s', nycFilename) + writeFileSync( + nycFilename, + JSON.stringify(nycCoverage, null, 2) + '\n', + 'utf8' + ) + } +} + module.exports = { showNycInfo, resolveRelativePaths, checkAllPathsNotFound, tryFindingLocalFiles, readNycOptions, - combineNycOptions, - defaultNycOptions + includeAllFiles } diff --git a/task.js b/task.js index 08c72a71..866cec0c 100644 --- a/task.js +++ b/task.js @@ -8,7 +8,8 @@ const { resolveRelativePaths, checkAllPathsNotFound, tryFindingLocalFiles, - readNycOptions + readNycOptions, + includeAllFiles } = require('./task-utils') const { fixSourcePaths } = require('./support-utils') const NYC = require('nyc') @@ -62,10 +63,13 @@ function maybePrintFinalCoverageFiles(folder) { } }) + const hasStatements = totalStatements > 0 const allCovered = coveredStatements === totalStatements + const coverageStatus = hasStatements ? (allCovered ? '✅' : '⚠️') : '❓' + debug( '%s %s statements covered %d/%d', - allCovered ? '✅' : '⚠️', + coverageStatus, key, coveredStatements, totalStatements @@ -165,6 +169,11 @@ const tasks = { // seems nyc API really is using camel cased version nycReportOptions.reportDir = nycReportOptions['report-dir'] + if (nycReportOptions.all) { + debug('nyc needs to report on all included files') + includeAllFiles(nycFilename, nycReportOptions) + } + debug('calling NYC reporter with options %o', nycReportOptions) debug('current working directory is %s', process.cwd()) const nyc = new NYC(nycReportOptions)