Saves the code coverage collected during Cypress tests
npm install -D @cypress/code-coverageNote: This plugin assumes that cypress is a peer dependency already installed in your project.
Then add the code below to the supportFile and setupNodeEvents function.
// cypress/support/e2e.js
import '@cypress/code-coverage/support'// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
require('@cypress/code-coverage/task')(on, config)
// include any other plugin code...
// It's IMPORTANT to return the config object
// with any changes
return config
},
},
})If your config file uses ES module syntax, such as a cypress.config.ts file or a project with "type": "module" in its package.json, you can import the task instead of calling require:
// cypress.config.ts
import { defineConfig } from 'cypress'
import codeCoverageTask from '@cypress/code-coverage/task'
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
codeCoverageTask(on, config)
return config
},
},
})Both forms work in either kind of config file. If TypeScript reports Cannot find module '@cypress/code-coverage/task', set "moduleResolution" to "bundler" in your tsconfig.json, or set both "module" and "moduleResolution" to "node16" or "nodenext". The plugin's entry points are only declared in the exports field of its package.json, and older module resolution settings don't read it.
This plugin DOES NOT instrument your code. You have to instrument it yourself using the Istanbul.js tool. Luckily, it is not difficult. For example, if you are already using Babel to transpile, you can add babel-plugin-istanbul to your .babelrc and instrument on the fly.
{
"plugins": ["istanbul"]
}Please see the Test Apps section below. You can find a linked project matching your situation to see how to instrument your application's source code before running end-to-end tests to get the code coverage.
If your application has been instrumented correctly, you should see additional counters and instructions in the application's JavaScript resources, as the image below shows.
You should see the window.__coverage__ object in the "Application under test iframe"
If you have instrumented your application's code and see the window.__coverage__ object, then this plugin will save the coverage into the .nyc_output folder and will generate reports after the tests finish (even in the interactive mode). Find the LCOV and HTML report in the coverage/lcov-report folder.
That should be it! You should see messages from this plugin in the Cypress Command Log.
The plugin doesn't depend on Babel. It reads whatever Istanbul-format coverage your code writes to window.__coverage__, so you can instrument with SWC instead by adding swc-plugin-coverage-instrument to your SWC config.
If you compile with @swc/core directly or through swc-loader, add the plugin to your .swcrc:
{
"jsc": {
"experimental": {
"plugins": [["swc-plugin-coverage-instrument", {}]]
}
}
}For Next.js, which compiles with SWC by default, add it to experimental.swcPlugins in next.config.js. Instrumented code is slower and larger, so turn it on only for the builds you test, for example with an environment variable:
// next.config.js
module.exports = {
experimental: {
swcPlugins:
process.env.INSTRUMENT_CODE === 'true'
? [['swc-plugin-coverage-instrument', {}]]
: []
}
}Then build with INSTRUMENT_CODE=true next build before running Cypress.
SWC plugins only load in the SWC version they were built for, and a mismatch makes the build fail when it loads the plugin. If that happens, try a different swc-plugin-coverage-instrument version that matches your @swc/core, or the SWC version bundled in your Next.js release. For example, swc-plugin-coverage-instrument 0.0.33 works with @swc/core 1.16.18 and with Next.js 16.4.3.
See test-apps/swc-webpack for a complete example.
- Read Cypress Code Coverage: Instrumenting code guide
- Watch Code coverage webinar
- Watch videos in Cypress Tips & Tricks that deal with code coverage
You need to instrument your web application. This means that when the test does cy.visit('localhost:3000') any code, the index.html requests should be instrumented by YOU. See the Test Apps section for advice. Usually, you need to stick babel-plugin-istanbul into your pipeline somewhere.
If you are testing individual functions from your application code by importing them directly into Cypress spec files, this is called "unit tests" and Cypress can instrument this scenario for you. See Instrument unit tests section.
The coverage folder has results in several formats, and the coverage raw data is stored in the .nyc_output folder. You can see the coverage numbers yourself. This plugin has nyc as a dependency, so it should be available right away. Here are common examples:
# see just the coverage summary
$ npx nyc report --reporter=text-summary
# see just the coverage file by file
$ npx nyc report --reporter=text
# save the HTML report again
$ npx nyc report --reporter=lcovIt is helpful to enforce minimum coverage numbers. For example:
$ npx nyc report --check-coverage --lines 80
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
$ npx nyc report --check-coverage --lines 101
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
ERROR: Coverage for lines (100%) does not meet global threshold (101%)The plugin can also check the thresholds from your NYC options at the end of the run. It's off by default. To turn it on, set checkCoverage: true in the expose.codeCoverage object:
// cypress.config.js
module.exports = defineConfig({
expose: {
codeCoverage: {
checkCoverage: true
}
}
})Set the thresholds the same way you would for nyc --check-coverage, for example in .nycrc.json:
{
"lines": 80,
"functions": 80,
"branches": 80,
"statements": 80,
"per-file": false
}When cypress run finishes, the plugin compares the coverage from all specs against lines, functions, branches, and statements. Any threshold you leave out uses the nyc default: 90% for lines and 0% for the rest. With per-file: true, each file is checked on its own. If any threshold isn't met, the run fails with a message such as:
Code coverage is below the threshold:
Coverage for lines (75%) does not meet global threshold (80%)
The reports are still written, so you can look at what's missing. A few things to know:
- The check runs in the
after:runevent, so it doesn't run incypress openunless you turn onexperimentalInteractiveRunEvents. - Cypress keeps only one handler per event. If your
setupNodeEventsregisters its ownafter:runhandler, one of the two replaces the other. - If you use a custom NYC command, the plugin doesn't check thresholds. Add
--check-coverageto that script instead.
If your NYC options set check-coverage but expose.codeCoverage.checkCoverage isn't on, the plugin prints a warning that the thresholds aren't enforced.
Watch the video How to read code coverage report to see how to read the HTML coverage report.
The plugin collects coverage from component tests, too. The setup is the same as for end-to-end tests, but it goes in your component testing configuration:
-
Import the support file in
cypress/support/component.js:// cypress/support/component.js import '@cypress/code-coverage/support'
-
Register the task in
component.setupNodeEvents:// cypress.config.js const { defineConfig } = require('cypress') module.exports = defineConfig({ component: { devServer: { framework: 'react', bundler: 'vite' }, setupNodeEvents(on, config) { require('@cypress/code-coverage/task')(on, config) return config } } })
-
Instrument the code your dev server serves. Cypress builds your components with the dev server you configure, so that's where Istanbul needs to run.
For Vite, add vite-plugin-istanbul to your Vite config. It instruments code served by the dev server by default:
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import istanbul from 'vite-plugin-istanbul'
export default defineConfig({
plugins: [
react(),
istanbul({
include: 'src/*',
exclude: ['node_modules', 'cypress', '**/*.cy.jsx'],
extension: ['.js', '.jsx']
})
]
})For webpack, add babel-plugin-istanbul to the Babel loader in the webpackConfig you pass to the dev server:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
component: {
devServer: {
framework: 'react',
bundler: 'webpack',
webpackConfig: {
resolve: { extensions: ['.js', '.jsx'] },
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-react', { runtime: 'automatic' }]],
plugins: ['istanbul']
}
}
}
]
}
}
},
setupNodeEvents(on, config) {
require('@cypress/code-coverage/task')(on, config)
return config
}
}
})babel-plugin-istanbul doesn't skip .cy.jsx spec files on its own, so exclude them in your NYC options, for example in .nycrc.json:
{
"exclude": ["**/*.cy.jsx", "cypress/**"]
}If instrumentation isn't working, the plugin logs "Could not find any coverage information in your application" after each test. To fail fast instead, check for the coverage object right after mounting:
it('mounts an instrumented component', () => {
cy.mount(<Counter />)
cy.window().should('have.property', '__coverage__')
})See test-apps/component-vite for a complete example.
If you test your application code directly from specs, you might want to instrument them and combine unit test code coverage with any end-to-end code coverage (from iframe). You can easily instrument spec files using babel-plugin-istanbul, for example.
Install the plugin
npm i -D babel-plugin-istanbulSet your .babelrc file.
{
"plugins": ["istanbul"]
}Put the following in the cypress/plugins/index.js file to use the .babelrc file.
module.exports = (on, config) => {
require('@cypress/code-coverage/task')(on, config)
on('file:preprocessor', require('@cypress/code-coverage/use-babelrc'))
return config
}The code coverage from spec files will be combined with end-to-end coverage.
Find examples of just the unit tests and JavaScript source files with collected code coverage in test-apps/unit-tests-js.
Example in test-apps/backend folder.
You can also instrument your server-side code and produce a combined coverage report that covers both the backend and frontend code.
- Run the server code with instrumentation. The simplest way is to use nyc. If normally you run
node src/server, then to run the instrumented version, you can donyc --silent node src/server. - Add an endpoint that returns collected coverage. If you are using Express, you can do
const express = require('express')
const app = express()
require('@cypress/code-coverage/middleware/express')(app)Tip: You can register the endpoint only if there is a global code coverage object, and you can exclude the middleware code from the coverage numbers
// https://github.com/gotwarlost/istanbul/blob/master/ignoring-code-for-coverage.md
/* istanbul ignore next */
if (global.__coverage__) {
require('@cypress/code-coverage/middleware/express')(app)
}If you use a Hapi server, define the endpoint yourself and return the object.
if (global.__coverage__) {
require('@cypress/code-coverage/middleware/hapi')(server)
}For any other server, define the endpoint yourself and return the coverage object:
if (global.__coverage__) {
// add method "GET /__coverage__" and response with JSON
onRequest = (response) => response.sendJSON({ coverage: global.__coverage__ })
}- Save the API coverage endpoint in the
cypress.jsonfile to let the plugin know where to call to receive the code coverage data from the server. Place it inexpose.codeCoverageobject:
{
"expose": {
"codeCoverage": {
"url": "http://localhost:3000/__coverage__"
}
}
}Or if you have multiple servers from which you are wanting to gather code coverage, you can pass an array to url as well:
{
"expose": {
"codeCoverage": {
"url": ["http://localhost:3000/__coverage__", "http://localhost:3001/__coverage__"]
}
}
}That should be enough - the code coverage from the server will be requested at the end of the test run and merged with the client-side code coverage, producing a combined report.
If there is NO frontend code coverage, and you only want to collect backend code coverage using Cypress tests, set expectBackendCoverageOnly: true in the cypress.json file. Otherwise, Cypress complains that it cannot find the frontend code coverage.
Default:
After:
{
"expose": {
"codeCoverage": {
"url": "http://localhost:3003/__coverage__",
"expectBackendCoverageOnly": true
}
}
}If there is ONLY frontend code coverage, set expectFrontendCoverageOnly: true in the cypress.json file. Otherwise, Cypress complains that it cannot find the frontend code coverage.
{
"expose": {
"codeCoverage": {
"url": "http://localhost:3003/__coverage__",
"expectFrontendCoverageOnly": true
}
}
}The plugin reads NYC options from the folder that holds your Cypress config file, because that's the working directory Cypress uses when it loads the config and runs setupNodeEvents. Most of the time that's your project root. But if you pass --config-file cypress/cypress.config.ts, the plugin looks in the cypress folder, not in the folder you started Cypress from.
The plugin looks for these files in that folder only. It doesn't search parent folders:
.nycrc.nycrc.json.nycrc.yaml.nycrc.ymlnyc.config.jsnyc.config.cjs- the
nycobject inpackage.json
Unlike the nyc CLI, which uses the first config file it finds, the plugin merges every file it finds. If two files set the same option, the one later in the list wins, so the nyc object in package.json overrides the rest. The coverage:report script is looked up in that same package.json. Relative paths such as report-dir, temp-dir, and the include and exclude globs are resolved against that folder as well.
For example, in a monorepo where you run cypress run --config-file cypress/cypress.config.ts from libs/foo, put the options next to the Cypress config rather than in libs/foo/package.json:
libs/foo/
├── package.json <- not read by the plugin
├── src/
└── cypress/
├── cypress.config.ts
└── .nycrc.json <- read by the plugin
{
"include": ["../src/**/*.ts"],
"report-dir": "../coverage"
}If you aren't sure which options the plugin picked up, run Cypress with DEBUG=code-coverage and look for the combined NYC options line. See Debugging.
You can specify a custom report folder by adding nyc object to the package.json file in the same folder as your Cypress config file. For example, to save reports to cypress-coverage folder, use:
{
"nyc": {
"report-dir": "cypress-coverage"
}
}You can specify custom coverage reporter(s) to use. For example, to output text summary and save JSON report in the cypress-coverage folder set in your package.json folder:
{
"nyc": {
"report-dir": "cypress-coverage",
"reporter": ["text", "json"]
}
}Tip: find list of reporters here
Sometimes, the NYC tool might be installed in a different folder, not the current or parent folder, or you might want to customize the report command. In that case, put the custom command into package.json in the same folder as your Cypress config file, and this plugin will automatically use it.
{
"scripts": {
"coverage:report": "call NYC report ..."
}
}When you split specs across several CI machines, for example with Cypress Cloud parallelization (cypress run --record --parallel), each machine only runs some of the specs. The plugin saves that machine's coverage to its own .nyc_output/out.json and writes a report from it, so each machine's report only shows part of your coverage. The plugin doesn't combine coverage across machines. Cypress Cloud doesn't either, so you combine the files in your CI pipeline:
- On each machine, run your tests, then save
.nyc_output/out.jsonas a CI artifact under a name unique to that machine. - Add one more job that runs after all the test machines finish. It downloads every file into one folder and runs
nyc reporton that folder.nyc reportreads every JSON file in its temp folder and merges them.
Here's what that looks like with GitHub Actions and three parallel containers:
jobs:
cypress-run:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
containers: [1, 2, 3]
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx cypress run --record --parallel
env:
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# give each container's coverage file a unique name, so the files
# don't overwrite each other when they're downloaded into one folder
- run: |
mkdir -p coverage-part
cp .nyc_output/out.json coverage-part/out-${{ matrix.containers }}.json
- uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.containers }}
path: coverage-part
coverage-report:
needs: cypress-run
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- uses: actions/download-artifact@v4
with:
pattern: coverage-*
path: .nyc_output
merge-multiple: true
- run: npx nyc report --reporter=lcov --reporter=text-summaryThe coverage folder from the last job holds the combined report. Upload it as an artifact or send it to a coverage service from there.
A few things to know:
- The coverage files store absolute paths to your source files. The report job needs the same source code at the same path as the test machines. With hosted CI runners that check out to the same folder every time, as in the example, this works on its own.
- If you enforce coverage thresholds, each machine checks only its part of the coverage and may fail even when the combined numbers pass. Leave
checkCoverageoff on the test machines and runnpx nyc report --check-coveragein the report job instead. - If the plugin can find your backend coverage, that coverage is merged into each machine's
out.jsontoo, so it's included in the combined report.
The cypress-example-conduit-app example follows the same steps on a different CI provider.
TypeScript source files should be automatically included in the report if they are instrumented.
See test-apps/ts-example, bahmutov/cra-ts-code-coverage-example or bahmutov/cypress-angular-coverage-example.
By default, the code coverage report includes only the instrumented files loaded by the application during the tests. If some modules are loaded dynamically or by the pages NOT visited during any tests, these files will not be in the report - because the plugin does not know about them. You can include all expected source files in the report using the include list in the package.json file. The files without counters will have 0 percent code coverage.
For example, to ensure the final report includes all JS files from the "src/pages" folder, set the "nyc" object in your package.json file.
{
"nyc": {
"all": true,
"include": "src/pages/*.js"
}
}See example test-app/all-files
You can exclude parts of the code or entire files from the code coverage report. See Istanbul guide. Common cases:
The "else" branch will never be hit when running code only during Cypress tests. Thus, we should exclude it from the branch coverage computation:
// expose "store" reference during tests
/* istanbul ignore else */
if (window.Cypress) {
window.store = store
}Often needed to skip a statement.
/* istanbul ignore next */
if (global.__coverage__) {
require('@cypress/code-coverage/middleware/express')(app)
}Or a particular switch case
switch (foo) {
case 1 /* some code */:
break
/* istanbul ignore next */
case 2: // really difficult to hit from tests
someCode()
}The code coverage plugin will automatically exclude any test/spec files you have defined in the testFiles (Cypress < v10) or specPattern (Cypress >= v10) configuration options. Additionally, you can set the exclude pattern glob in the code coverage configuration key to specify additional files to be excluded:
// cypress.config.js or cypress.json
expose: {
codeCoverage: {
exclude: ['cypress/**/*.*'],
},
},Cypress 10 and later users should set the exclude option to exclude any items from the cypress folder they don't want included in the coverage reports.
Additionally, you can use nyc configuration and include and exclude options. You can include and exclude files using minimatch patterns in the .nycrc file or the "nyc" object inside your package.json file. Whichever you use, put it in the same folder as your Cypress config file.
For example, if you want only to include files in the app folder but exclude the app/util.js file, you can set it in your package.json.
{
"nyc": {
"include": ["app/**/*.js"],
"exclude": ["app/util.js"]
}
}Note: If you have the 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 the include list, then an empty placeholder will be included. See PR 208.
Another important option is excludeAfterRemap. By default, it is false, which might let excluded files through. If you exclude the files, and the instrumenter does not respect the nyc.exclude setting, then add excludeAfterRemap: true to tell nyc report to exclude files. See test-apps/exclude-files.
You can skip the client-side code coverage hooks by setting the exposed coverage value to false.
# tell Cypress to set the exposed variable "coverage" to false
cypress run --expose coverage=falseOr set it to false in the cypress.json file.
{
"expose": {
"coverage": false
}
}See Cypress environment variables and support.js. You can try running without code coverage in this project yourself
# run with code coverage
npm run dev
# disable code coverage
npm run dev:no:coverage- Read the Cypress code coverage guide
- Read "Code Coverage by Parcel Bundler" blog post
- Read "Combined End-to-end and Unit Test Coverage"
- If you are using React, check out @cypress/instrument-cra
- Watch videos in Cypress Tips & Tricks playlist
Full examples we use for testing in this repository:
- test-apps/backend only instruments the backend Node server and saves the coverage report
- test-apps/fullstack instruments and merges backend, e2e and unit test coverage into a single report
- test-apps/before-all-visit checks if code coverage works when
cy.visitis made once in thebeforehook - test-apps/before-each-visit checks if code coverage correctly keeps track of code when doing
cy.visitbefore each test - test-apps/one-spec confirms that coverage is collected and filtered correctly if the user only executes a single Cypress test
- test-apps/ts-example uses Babel + Parcel to instrument and serve TypeScript file
- test-apps/esm-example demonstrates using ES module syntax (
import/export) with the plugin - test-apps/use-webpack shows Webpack build with source maps and Babel
- test-apps/component-vite collects coverage from React component tests served by Vite
- test-apps/swc-webpack instruments a webpack build with SWC instead of Babel, and loads it after the page's
loadevent - test-apps/unit-tests-js runs just the unit tests and reports code coverage (JavaScript source code)
- test-apps/unit-tests-ts runs just the unit tests and reports code coverage (TypeScript source code)
Look up the list of examples under the GitHub topic cypress-code-coverage-example
- cypress-io/cypress-realworld-app is an easy to set up and run a real-world application with E2E, API, and unit tests that achieves 100% code-coverage for both front and back end code. Its CI pipeline also reports code-coverage reports across parallelized test runs to Codecov.
- cypress-io/cypress-example-todomvc-redux is a React / Redux application with 100% code coverage.
- cypress-io/cypress-example-conduit-app shows how to collect the coverage information from both back and frontend code and merge it into a single report. The E2E test step runs parallel in several CI containers, each saving just partial test coverage information. Then, a merge job runs, taking artifacts and combining coverage into the final report to be sent to an external coverage as a service app.
- bahmutov/code-coverage-webpack-dev-server shows how to collect code coverage from an application that uses webpack-dev-server.
- bahmutov/code-coverage-vue-example collects code coverage for Vue.js single file components.
- lluia/cypress-typescript-coverage-example shows coverage for React App that uses TypeScript. See discussion in issue #19.
- bahmutov/cypress-and-jest shows how to run Jest unit tests and Cypress unit tests, collecting code coverage from both test runners and then producing a merged report.
- bahmutov/cypress-angular-coverage-example forked from skylock/cypress-angular-coverage-example shows Angular 8 + TypeScript application with instrumentation done using istanbul-instrumenter-loader.
- bahmutov/testing-react shows how to get code coverage for a React application created using CRA v3 without ejecting
react-scripts. - bahmutov/cra-ts-code-coverage-example instruments TypeScript React application on the fly without ejecting
react-scriptsby using @cypress/instrument-cra. - bahmutov/next-and-cypress-example shows how to get backend and frontend coverage for a Next.js project. Uses middleware/nextjs.js.
- kylemh/next-ts-with-cypress-coverage This example project contains Next.js with TypeScript, instrumented coverage reporting, @testing-library/react, and instructions on how to type custom commands.
- akoidan/vue-webpack-typescript Pure webpack config with vue + typescript with codecov reports. This setup uses a babel-loader with a TS checker as a separate thread.
- bahmutov/code-coverage-subfolder-example shows how to instrument the
appfolder usingnyc instrumentas a separate step before running E2E tests - bahmutov/docker-with-cypress-included-code-coverage-example runs tests inside pre-installed Cypress using cypress/included:x.y.z Docker image and reports code coverage.
- bahmutov/app-in-docker-coverage-example shows an app running inside a Docker container, while Cypress runs on the local machine. Before generating the report, Cypress can still discover the source files.
- bahmutov/gatsby-cypress-with-code-coverage shows code coverage using the official Gatsby "Hello World" starter.
- muratkeremozcan/angular-playground is an Angular TypeScript application with combined unit and E2E coverage.
- nefayran/cypress-react-vite React with Vite and Istanbul plugin for code coverage.
Cypress.env() was deprecated in Cypress v15.10.0, and will be removed in Cypress 16. This necessitates a breaking change to how you configure @cypress/code-coverage.
// BEFORE
// Configure in the `env` key in your Cypress config:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
env: {
codeCoverage: {
url: 'http://localhost:1234/__coverage__',
exclude: 'cypress/**/*.*'
}
}
})// AFTER
// Configure in the `expose` key in your Cypress config:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
expose: {
codeCoverage: {
url: 'http://localhost:1234/__coverage__',
exclude: 'cypress/**/*.*'
}
}
})With the removal of the plugins directory in Cypress version 10+, you'll need to add all of your configuration into the configuration file (cypress.config.js by default).
// BEFORE
// Register tasks in your `cypress/plugins/index.js` file.
module.exports = (on, config) => {
require('@cypress/code-coverage/task')(on, config)
// add other tasks to be registered here
// IMPORTANT to return the config object
// with the any changes
return config
}// AFTER
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
require('@cypress/code-coverage/task')(on, config)
// include any other plugin code...
// It's IMPORTANT to return the config object
// with any changes
return config
},
},
})Change the plugins file cypress/plugins/index.js
// BEFORE
module.exports = (on, config) => {
on('task', require('@cypress/code-coverage/task'))
}
// AFTER
module.exports = (on, config) => {
require('@cypress/code-coverage/task')(on, config)
// IMPORTANT to return the config object
// with the any changes
return config
}Tip: We include plugins.js file you can point at from your code in simple cases. From your cypress.json file:
{
"pluginsFile": "node_modules/@cypress/code-coverage/plugins",
"supportFile": "node_modules/@cypress/code-coverage/support"
}This plugin uses the debug module to output additional logging messages from its task.js file. This can help with debugging errors while saving code coverage or reporting. To see these messages, run Cypress from the terminal with the environment variable DEBUG=code-coverage. Example using Unix syntax to set the variable:
$ DEBUG=code-coverage npm run dev
...
code-coverage reset code coverage in interactive mode +0ms
code-coverage wrote coverage file /code-coverage/.nyc_output/out.json +28ms
code-coverage saving coverage report using the command: "nyc report --report-dir ./coverage --reporter=lcov --reporter=clover --reporter=json" +3msDeeply nested objects will sometimes have [object Object] values printed. You can print these nested objects by specifying a deeper depth by adding DEBUG_DEPTH= setting.
DEBUG_DEPTH=10 DEBUG=code-coverage npm run devCommon issue: not instrumenting your application when running Cypress.
If the plugin worked before in version X but stopped after upgrading to version Y, please try the released versions between X and Y to see where the breaking change was.
If you decide to open an issue in this repository, please fill in all information the issue template asks for. The issues most likely to be resolved have debug logs, screenshots, and hopefully public repository links so we can try running the tests ourselves.
If you get a coverage report on your machine but an empty one in CI, the app that CI tests is almost always not instrumented. You'll see this in the Command Log:
⚠️ Could not find any coverage information in your application
And this in the terminal:
⚠️ file .nyc_output/out.json has no coverage information
Versions before 3.13.4 printed Cannot find coverage file .nyc_output/out.json instead.
Locally you probably run a dev server, while CI often builds the app for production first. Many instrumentation setups only switch on in development. For example:
-
Babel: an
istanbulplugin listed under"env": { "development": ... }or"env": { "test": ... }in your Babel config only runs whenBABEL_ENVorNODE_ENVmatches that name. Production builds usually setNODE_ENV=production. -
vite-plugin-istanbul: by default, it only instruments code served byvite devand skipsvite build. SetforceBuildInstrument: trueto instrument builds too. Pair it withrequireEnv: trueso only builds withVITE_COVERAGE=trueget instrumented, and your real production build stays clean:// vite.config.js import { defineConfig } from 'vite' import istanbul from 'vite-plugin-istanbul' export default defineConfig({ plugins: [ istanbul({ requireEnv: true, forceBuildInstrument: true }) ] })
Then build with
VITE_COVERAGE=true vite buildin CI.
To catch this early, add a test that fails when the page has no coverage object, and run it in CI:
// cypress/e2e/instrumentation.cy.js
it('loads an instrumented app', () => {
cy.visit('/')
cy.window().should('have.property', '__coverage__')
})If the plugin times out when sending coverage report data to be merged, this may be due to a very large
report being sent across processes. You can batch the report by setting the sendCoverageBatchSize value in your cypress.config.js file's expose section. Assign the variable an integer value representing
the number of report keys to send per batch.
You can test changes locally by running tests and confirming that the code coverage has been calculated and saved.
npm run test:ci
# now check generated coverage numbers
npx nyc report --check-coverage true --lines 80
npx nyc report --check-coverage true --lines 100 --include cypress/about.js
npx nyc report --check-coverage true --lines 100 --include cypress/unit.jsTip: use check-code-coverage for stricter code coverage checks than nyc report --check-coverage allows.
You can validate links in Markdown files in this directory by executing (Linux + Mac only) script.
npm run check:markdownThis project is licensed under the terms of the MIT license.





