Skip to main content

Writing a Plugin

The Plugins API allows you to hook into and extend Cypress behavior.

info

Note: This document assumes you have read the Plugins Guide.

caution

Deprecated

Configuring plugins via cypress/plugins/index.js is no longer supported as of Cypress version 10.0.0.

We recommend that you update your configuration. Please see the plugins guide and the migration guide for more information on how to update your configuration.

Plugins API

The setupNodeEvents function (or deprecated plugins file function) receives 2 arguments: on and config. It can return a synchronous value or can also return a Promise, which will be awaited until it resolves. This enables you to perform asynchronous actions such as reading files in from the filesystem.

If you return or resolve with an object, Cypress will then merge this object into the config which enables you to overwrite configuration or environment variables.

const { defineConfig } = require('cypress')

module.exports = defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
// configure plugins here
},
},
})

on

on is a function that you will use to register listeners on various events that Cypress exposes.

Registering to listen on an event looks like this:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
on('<event>', (arg1, arg2) => {
// plugin stuff here
})
},
},
})

Each event documents its own argument signature. To understand how to use them, please refer to the docs for each one.

config

config is the resolved Cypress configuration of the opened project.

This configuration contains all of the values that get passed into the browser for your project.

Some plugins may utilize or require these values, so they can take certain actions based on the configuration. If these values are programmatically modified, Cypress will use the new values.

caution

The config object also includes the following extra values that are not part of the standard configuration. These values are read only and cannot be modified from the plugins file.

  • configFile: The absolute path to the Cypress configuration file. See the --config-file and configFile docs for more information on this value.
  • projectRoot: The absolute path to the root of the project (e.g. /Users/me/dev/my-project)
  • version: The version number of Cypress. This can be used to handle breaking changes.

Please check out our API docs for modifying configuration here.

List of events

The following events are available:

EventDescription
after:runOccurs after the run is finished.
after:screenshotOccurs after a screenshot is taken.
after:specOccurs after a spec is finished running.
before:browser:launchOccurs immediately before launching a browser.
before:runOccurs before the run starts.
before:specOccurs when a spec is about to be run.
file:preprocessorOccurs when a spec or spec-related file needs to be transpiled for the browser.
taskOccurs in conjunction with the cy.task command.

Execution context

The setupNodeEvents function (or deprecated plugins file function) is invoked when Cypress opens a project.

Cypress does this by spawning an independent child_process which then requires the Cypress configuration file. This is similar to the way Visual Studio Code or Atom works.

This code will be executed using the the Node version that launched Cypress.

npm modules

When Cypress executes the setupNodeEvents function (or deprecated plugins file function) it will execute with process.cwd() set to your project's path. Additionally - you will be able to require any node module you have installed, including local files inside your project.

For example, if your package.json looked like this:

{
"name": "My Project",
"dependencies": {
"debug": "x.x.x"
},
"devDependencies": {
"lodash": "x.x.x"
}
}

Then you could do any of the following in your setupNodeEvents function:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
const _ = require('lodash') // yup, dev dependencies
const path = require('path') // yup, core node library
const debug = require('debug') // yup, dependencies
const User = require('./lib/models/user') // yup, relative local modules

console.log(__dirname) // /Users/janelane/Dev/my-project
console.log(process.cwd()) // /Users/janelane/Dev/my-project
},
},
})

Error handling

The Cypress configuration file is loaded in its own child process so it is isolated away from the context that Cypress itself runs in. That means you cannot accidentally modify or change Cypress's own execution in any way.

If your setupNodeEvents function (or deprecated plugins file function) has an uncaught exception, an unhandled rejection from a promise, or a syntax error - Cypress will automatically catch those and display them to you inside of the console and even in Cypress itself.

Errors in your setupNodeEvents function will not crash Cypress.

File changes

Normally when writing code in Node, you typically have to restart the process after changing any files.

Cypress automatically watches your Cypress configuration file and any changes made will take effect immediately. We will read the file in and execute the exported function again.

This enables you to iterate on plugin code even with Cypress already running.