@cypress/code-coverage
Advanced tools
{ | ||
"name": "@cypress/code-coverage", | ||
"version": "3.9.12", | ||
"version": "3.10.0-dev.1", | ||
"description": "Saves the code coverage collected during Cypress tests", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "cypress run", | ||
"start": "parcel serve cypress/index.html", | ||
"coverage:verify": "npx nyc report --check-coverage true --lines 80", | ||
"cy:open": "cypress open", | ||
"dev": "start-test 1234 cy:open", | ||
"semantic-release": "semantic-release", | ||
"test:ci": "start-test 1234", | ||
"test": "start-test 1234 'npx cypress run'", | ||
"report:coverage": "nyc report --reporter=html", | ||
@@ -18,4 +18,3 @@ "dev:no:coverage": "start-test 1234 'cypress open --env coverage=false'", | ||
"check:markdown": "find *.md -exec npx markdown-link-check {} \\;", | ||
"effective:config": "circleci config process .circleci/config.yml | sed /^#/d", | ||
"types": "tsc --noEmit --allowJs *.js cypress/integration/*.js" | ||
"effective:config": "circleci config process .circleci/config.yml | sed /^#/d" | ||
}, | ||
@@ -51,3 +50,4 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@cypress/browserify-preprocessor": "3.0.2", | ||
"@cypress/webpack-preprocessor": "^5.11.0", | ||
"chalk": "4.1.2", | ||
"dayjs": "1.10.7", | ||
@@ -59,16 +59,12 @@ "debug": "4.3.3", | ||
"js-yaml": "3.14.1", | ||
"nyc": "15.1.0", | ||
"chalk": "4.1.2" | ||
"nyc": "15.1.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "7.16.0", | ||
"@babel/preset-typescript": "7.16.0", | ||
"@cypress/webpack-preprocessor": "5.10.0", | ||
"babel-loader": "8.2.3", | ||
"@babel/core": "^7.16.0", | ||
"@babel/preset-env": "^7.16.11", | ||
"babel-loader": "^8.2.3", | ||
"babel-plugin-istanbul": "6.1.1", | ||
"browserify-istanbul": "3.0.1", | ||
"check-code-coverage": "1.10.0", | ||
"console-log-div": "0.6.3", | ||
"cypress": "9.1.0", | ||
"express": "4.17.1", | ||
"cypress": "^9.4.1", | ||
"lodash": "4.17.21", | ||
@@ -79,9 +75,5 @@ "markdown-link-check": "3.9.0", | ||
"semantic-release": "17.4.7", | ||
"serve": "11.3.2", | ||
"start-server-and-test": "1.14.0", | ||
"ts-loader": "8.3.0", | ||
"typescript": "4.5.2", | ||
"webpack": "4.46.0", | ||
"webpack-cli": "3.3.12" | ||
"webpack": "^5.68.0" | ||
} | ||
} |
@@ -338,4 +338,17 @@ # @cypress/code-coverage [![renovate-app badge][renovate-badge]][renovate-app] [](https://circleci.com/gh/cypress-io/code-coverage) | ||
See [`nyc` configuration](https://github.com/istanbuljs/nyc#common-configuration-options) and [ include and exclude options](https://github.com/istanbuljs/nyc#using-include-and-exclude-arrays). You can include and exclude files using `minimatch` patterns in `.nycrc` file or using "nyc" object inside your `package.json` file. | ||
The code coverage plugin will automatically exclude any test/spec files you have defined in `testFiles` (Cypress < v10) or `specPattern` (Cypress >= v10) configuration options. Additionaly, you can set the `exclude` pattern glob in the code coverage environment variable to specify additional files to be excluded: | ||
```javascript | ||
// cypress.config.js or cypress.json | ||
env: { | ||
codeCoverage: { | ||
exclude: ['cypress/**/*.*'], | ||
}, | ||
}, | ||
``` | ||
Cypress v10 and later users should set the `exclude` option to exclude any items from the `cypress` folder they don't want to be included in the coverage reports. | ||
Additionaly, you can use [`nyc` configuration](https://github.com/istanbuljs/nyc#common-configuration-options) and [include and exclude options](https://github.com/istanbuljs/nyc#using-include-and-exclude-arrays). You can include and exclude files using `minimatch` patterns in `.nycrc` file or using "nyc" object inside your `package.json` file. | ||
For example, if you want to only include files in the `app` folder, but exclude `app/util.js` file, you can set in your `package.json` | ||
@@ -342,0 +355,0 @@ |
@@ -5,2 +5,14 @@ // @ts-check | ||
/** excludes files that shouldn't be in code coverage report */ | ||
const filterFilesFromCoverage = ( | ||
totalCoverage, | ||
config = Cypress.config, | ||
env = Cypress.env, | ||
spec = Cypress.spec | ||
) => { | ||
const withoutSpecs = filterSpecsFromCoverage(totalCoverage, config, env, spec) | ||
const appCoverageOnly = filterSupportFilesFromCoverage(withoutSpecs, config) | ||
return appCoverageOnly | ||
} | ||
/** | ||
@@ -10,21 +22,15 @@ * remove coverage for the spec files themselves, | ||
*/ | ||
const filterSpecsFromCoverage = (totalCoverage, config = Cypress.config) => { | ||
const integrationFolder = config('integrationFolder') | ||
/** @type {string} Cypress run-time config has test files string pattern */ | ||
// @ts-ignore | ||
const testFilePattern = config('testFiles') | ||
const filterSpecsFromCoverage = ( | ||
totalCoverage, | ||
config = Cypress.config, | ||
env = Cypress.env, | ||
spec = Cypress.spec | ||
) => { | ||
const testFilePatterns = getCypressExcludePatterns(config, env, spec) | ||
// test files chould be: | ||
// wild card string "**/*.*" (default) | ||
// wild card string "**/*spec.js" | ||
// list of wild card strings or names ["**/*spec.js", "spec-one.js"] | ||
const testFilePatterns = Array.isArray(testFilePattern) | ||
? testFilePattern | ||
: [testFilePattern] | ||
const isUsingDefaultTestPattern = testFilePattern === '**/*.*' | ||
const isTestFile = (filename) => { | ||
const isTestFile = (_, filePath) => { | ||
const workingDir = spec.absolute.replace(spec.relative, '') | ||
const filename = filePath.replace(workingDir, '') | ||
const matchedPattern = testFilePatterns.some((specPattern) => | ||
Cypress.minimatch(filename, specPattern) | ||
Cypress.minimatch(filename, specPattern, { debug: false }) | ||
) | ||
@@ -37,11 +43,90 @@ const matchedEndOfPath = testFilePatterns.some((specPattern) => | ||
const isInIntegrationFolder = (filename) => | ||
filename.startsWith(integrationFolder) | ||
const coverage = Cypress._.omitBy(totalCoverage, isTestFile) | ||
return coverage | ||
} | ||
const isA = (fileCoverge, filename) => isInIntegrationFolder(filename) | ||
const isB = (fileCoverge, filename) => isTestFile(filename) | ||
/** | ||
* Reads Cypress config and exclude patterns and combines them into one array | ||
* @param {*} config | ||
* @param {*} env | ||
* @returns string[] | ||
*/ | ||
function getCypressExcludePatterns(config, env, spec) { | ||
let testFilePatterns = [] | ||
const isTestFileFilter = isUsingDefaultTestPattern ? isA : isB | ||
const testFilePattern = config('specPattern') || config('testFiles') | ||
const excludePattern = env().codeCoverage && env().codeCoverage.exclude | ||
const coverage = Cypress._.omitBy(totalCoverage, isTestFileFilter) | ||
if (Array.isArray(testFilePattern)) { | ||
testFilePatterns = testFilePattern | ||
} else { | ||
testFilePatterns = [testFilePattern] | ||
} | ||
// combine test files pattern and exclude patterns into single exclude pattern | ||
if (Array.isArray(excludePattern)) { | ||
testFilePatterns = [...testFilePatterns, ...excludePattern] | ||
} else if (excludePattern) { | ||
testFilePatterns = [...testFilePatterns, excludePattern] | ||
} | ||
// Cypress <v10 might have integration folder with default **/*.* pattern, | ||
// if so, exclude those files | ||
let integrationFolder = config('integrationFolder') | ||
if (integrationFolder) { | ||
const workingDir = spec.absolute.replace(spec.relative, '') | ||
integrationFolder = integrationFolder.replace(workingDir, '') | ||
testFilePatterns.forEach((pattern, idx) => { | ||
if (pattern === '**/*.*') { | ||
testFilePatterns[idx] = `${integrationFolder}/${pattern}`.replace( | ||
'//', | ||
'/' | ||
) | ||
} | ||
}) | ||
} | ||
return testFilePatterns | ||
} | ||
/** | ||
* Removes support file from the coverage object. | ||
* If there are more files loaded from support folder, also removes them | ||
*/ | ||
const filterSupportFilesFromCoverage = ( | ||
totalCoverage, | ||
config = Cypress.config | ||
) => { | ||
const integrationFolder = config('integrationFolder') | ||
/** | ||
* Cypress v10 doesn't have an integrationFolder config value any more, so we nope out here if its undefined. | ||
* Instead, we rely on the new exclude option logic done in the getCypressExcludePatterns function. | ||
*/ | ||
if (!integrationFolder) { | ||
return totalCoverage | ||
} | ||
const supportFile = config('supportFile') | ||
/** @type {string} Cypress run-time config has the support folder string */ | ||
// @ts-ignore | ||
const supportFolder = config('supportFolder') | ||
const isSupportFile = (filename) => filename === supportFile | ||
let coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => | ||
isSupportFile(filename) | ||
) | ||
// check the edge case | ||
// if we have files from support folder AND the support folder is not same | ||
// as the integration, or its prefix (this might remove all app source files) | ||
// then remove all files from the support folder | ||
if (!integrationFolder.startsWith(supportFolder)) { | ||
// remove all covered files from support folder | ||
coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => | ||
filename.startsWith(supportFolder) | ||
) | ||
} | ||
return coverage | ||
@@ -70,3 +155,3 @@ } | ||
fixSourcePaths, | ||
filterSpecsFromCoverage | ||
filterFilesFromCoverage | ||
} |
@@ -6,3 +6,3 @@ /// <reference types="cypress" /> | ||
var duration = require('dayjs/plugin/duration') | ||
const { filterSpecsFromCoverage } = require('./support-utils') | ||
const { filterFilesFromCoverage } = require('./support-utils') | ||
@@ -18,7 +18,6 @@ dayjs.extend(duration) | ||
const withoutSpecs = filterSpecsFromCoverage(coverage) | ||
const appCoverageOnly = filterSupportFilesFromCoverage(withoutSpecs) | ||
const totalCoverage = filterFilesFromCoverage(coverage) | ||
// stringify coverage object for speed | ||
cy.task('combineCoverage', JSON.stringify(appCoverageOnly), { | ||
cy.task('combineCoverage', JSON.stringify(totalCoverage), { | ||
log: false | ||
@@ -37,33 +36,2 @@ }) | ||
/** | ||
* Removes support file from the coverage object. | ||
* If there are more files loaded from support folder, also removes them | ||
*/ | ||
const filterSupportFilesFromCoverage = (totalCoverage) => { | ||
const integrationFolder = Cypress.config('integrationFolder') | ||
const supportFile = Cypress.config('supportFile') | ||
/** @type {string} Cypress run-time config has the support folder string */ | ||
// @ts-ignore | ||
const supportFolder = Cypress.config('supportFolder') | ||
const isSupportFile = (filename) => filename === supportFile | ||
let coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => | ||
isSupportFile(filename) | ||
) | ||
// check the edge case | ||
// if we have files from support folder AND the support folder is not same | ||
// as the integration, or its prefix (this might remove all app source files) | ||
// then remove all files from the support folder | ||
if (!integrationFolder.startsWith(supportFolder)) { | ||
// remove all covered files from support folder | ||
coverage = Cypress._.omitBy(totalCoverage, (fileCoverage, filename) => | ||
filename.startsWith(supportFolder) | ||
) | ||
} | ||
return coverage | ||
} | ||
const registerHooks = () => { | ||
@@ -70,0 +38,0 @@ let windowCoverageObjects |
@@ -1,9 +0,5 @@ | ||
const browserify = require('@cypress/browserify-preprocessor') | ||
// TODO check if there is .babelrc file | ||
// if not, maybe create one? | ||
// Tells Cypress to use .babelrc when bundling spec code | ||
const options = browserify.defaultOptions | ||
options.browserifyOptions.transform[1][1].babelrc = true | ||
module.exports = browserify(options) | ||
const webpackPreprocessor = require('@cypress/webpack-preprocessor') | ||
const defaults = webpackPreprocessor.defaultOptions | ||
// remove presets so the babelrc file will be used | ||
delete defaults.webpackOptions.module.rules[0].use[0].options.presets | ||
module.exports = webpackPreprocessor(defaults) |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
63111
2.32%14
-33.33%1029
4.15%531
2.51%13
-7.14%1
Infinity%