Skip to content

Cypress is a test runner built for the modern web. It has a lot of great features:

  • Time travel
  • Real-time reloads
  • Automatic waiting
  • Spies, stubs, and clocks
  • Network traffic control
  • Screenshots and videos

The @nx/cypress plugin supports the following package versions.

PackageSupported Versions
cypress>= 13 < 17

Nx generators install the latest supported versions automatically when scaffolding new projects.

For Cypress Component Testing, see the component testing guide.

In any Nx workspace, you can install @nx/cypress by running the following command:

Terminal window
nx add @nx/cypress

This will install the correct version of @nx/cypress.

The @nx/cypress plugin will create a task for any project that has a Cypress configuration file present. Any of the following files will be recognized as a Cypress configuration file:

  • cypress.config.js
  • cypress.config.ts
  • cypress.config.mjs
  • cypress.config.cjs

The configuration directory must also contain a package.json or project.json.

To view inferred tasks for a project, open the project details view in Nx Console or run nx show project my-project --web in the command line.

The @nx/cypress/plugin is configured in the plugins array in nx.json.

nx.json
{
"plugins": [
{
"plugin": "@nx/cypress/plugin",
"options": {
"targetName": "e2e",
"ciTargetName": "e2e-ci",
"componentTestingTargetName": "component-test",
"ciComponentTestingTargetName": "component-test-ci",
"openTargetName": "open-cypress"
}
}
]
}

The options shown above control the names of the inferred Cypress tasks. The following table shows the default values for each option:

OptionDefault
targetName"e2e"
ciTargetName"e2e-ci"
componentTestingTargetName"component-test"
ciComponentTestingTargetNameundefined (task is not inferred by default)
openTargetName"open-cypress"

The e2e and component-test tasks are cached and track Cypress screenshot and video outputs. The openTargetName task opens the interactive Cypress application. The ciTargetName task uses the Atomizer. Set ciComponentTestingTargetName to atomize component tests as well.

Use include and exclude glob patterns on the plugin entry to scope inference. A target defaults plugin filter must use the exact identifier @nx/cypress/plugin.

The e2e tasks wait for the dev server task's readyWhen check before Cypress starts. nxE2EPreset then takes the protocol and port from the address the server reported in NX_READY_URL, and keeps the path and query of baseUrl. A localhost host stays as it is when the server listens on a loopback address. Any other host moves to the one the server reported. nxE2EPreset keeps a baseUrl set with CYPRESS_BASE_URL, or a --config value other than the one Cypress would use anyway: the config file's baseUrl, or ciBaseUrl in e2e-ci tasks. Nx still starts the dev server. The preset waits up to webServerConfig.timeout (60 seconds by default) for that baseUrl to respond, then Cypress tests against it. To start Cypress as soon as the dev server task starts instead, set the waitForServerReady plugin option to false:

nx.json
{
"plugins": [
{
"plugin": "@nx/cypress/plugin",
"options": {
"waitForServerReady": false
}
}
]
}

The option is deprecated and will be removed in Nx 25, when the e2e tasks always wait.

The plugin infers the dependency on the dev server from webServerCommands in nxE2EPreset. In a config without nxE2EPreset, add the dependency with waitFor set to ready yourself:

apps/myapp-e2e/project.json
{
"targets": {
"e2e": {
"dependsOn": [
{ "projects": ["myapp"], "target": "serve", "waitFor": "ready" }
]
}
}
}

Then pass baseUrl through getReadyUrl from @nx/devkit. It returns the address unchanged when Nx reports none, and otherwise moves it to the reported port:

apps/myapp-e2e/cypress.config.ts
import { defineConfig } from 'cypress';
import { getReadyUrl } from '@nx/devkit';
export default defineConfig({
e2e: {
baseUrl: getReadyUrl('http://localhost:4200'),
},
});

To enable e2e task splitting, make sure there is a ciWebServerCommand property set in your cypress.config.ts file. It will look something like this:

apps/my-project-e2e/cypress.config.ts
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
export default defineConfig({
e2e: {
...nxE2EPreset(__filename, {
cypressDir: 'src',
bundler: 'vite',
webServerCommands: {
default: 'nx run my-project:serve',
production: 'nx run my-project:preview',
},
ciWebServerCommand: 'nx run my-project:serve-static',
}),
baseUrl: 'http://localhost:4200',
},
});

An atomized task reruns when the app, any project the app depends on, or any test file changes. To scope it to the code its test file exercises, see skip unaffected split e2e tests.

The @nx/cypress/plugin can also automatically split your component testing tasks by file. To enable it, set the ciComponentTestingTargetName option of the @nx/cypress/plugin in your nx.json file. It will look something like this:

nx.json
{
"plugins": [
{
"plugin": "@nx/cypress/plugin",
"options": {
"targetName": "e2e",
"ciTargetName": "e2e-ci",
"componentTestingTargetName": "component-test",
"ciComponentTestingTargetName": "component-test-ci",
"openTargetName": "open-cypress"
}
}
]
}

By default, when creating a new frontend application, Nx will use Cypress to create the e2e tests project.

Terminal window
nx g @nx/web:app apps/frontend

To configure Cypress for an existing project, run the following generator:

Terminal window
nx g @nx/cypress:configuration --project=your-app-name

Optionally, you can use the --baseUrl option if you don't want the Cypress plugin to serve your-app-name.

Terminal window
nx g @nx/cypress:configuration --project=your-app-name --baseUrl=http://localhost:4200

Replace your-app-name with the app's name as defined in your project.json file or the name property of your package.json.

Most application generators pass two servers to the Cypress configuration: the dev server for local runs and a production build for CI. When the two differ, the generated config reads the CI environment variable and picks between them.

// apps/<your-app-name>-e2e/cypress.config.ts
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
export default defineConfig({
e2e: {
...nxE2EPreset(import.meta.url, {
cypressDir: 'src',
bundler: 'vite',
webServerCommands: {
default: process.env['CI']
? 'npx nx run <your-app-name>:preview'
: 'npx nx run <your-app-name>:dev',
production: 'npx nx run <your-app-name>:preview',
},
ciWebServerCommand: 'npx nx run <your-app-name>:preview',
ciBaseUrl: 'http://localhost:4300',
}),
baseUrl: process.env['CI']
? 'http://localhost:4300'
: 'http://localhost:4200',
},
});

nx e2e runs against the dev server locally, which avoids a rebuild on every change, and against a production build in CI. The e2e-ci tasks always run against ciWebServerCommand.

These applications run against the dev server in CI as well:

  • React applications that use React Router (--useReactRouter)
  • Expo applications

Web applications generated with --bundler=none have no dev server, so they run against serve-static locally as well.

The inferred e2e task includes the CI environment variable in its inputs, so local and CI runs don't share cached results. An inputs list you set for this task in targetDefaults or in a project configuration replaces the inferred inputs unless it contains "...". Add { "env": "CI" } to that list, or add "..." to keep the inferred inputs.

Run nx e2e frontend-e2e to execute e2e tests with Cypress.

You can run your e2e test against a production build by using the production configuration

Terminal window
nx e2e frontend-e2e --configuration=production

You can use the --spec flag to glob for test files.

Terminal window
# run the tests in the smoke/ directory
nx e2e frontend-e2e --spec="**smoke/**"
# run the tests in smoke/ directory and with dashboard in the file name
nx e2e frontend-e2e --spec="**smoke/**,**dashboard.cy**"

By default, Cypress will run in headless mode. You will have the result of all the tests and errors (if any) in your terminal. Screenshots and videos will be accessible in dist/cypress/apps/frontend/screenshots and dist/cypress/apps/frontend/videos.

You can also run Cypress in headed mode and watching for changes. This is a great way to enhance the dev workflow. You can build up test files with the application running and Cypress will re-run those tests as you enhance and add to the suite.

Terminal window
nx open-cypress frontend-e2e

The baseUrl property provides you the ability to test an application hosted on a specific domain.

Terminal window
nx e2e frontend-e2e --config="baseUrl=https://frontend.com"

If you need to fine tune your Cypress setup, you can do so by modifying cypress.config.ts in the project root. For instance, you can add your projectId to save all the screenshots and videos into your Cypress dashboard. The complete configuration is documented on the official website.

For adding more dynamic configurations to your Cypress configuration, you can look into using setupNodeEvents configuration option.

If you need to pass a variable to Cypress that you don't want to commit to your repository (i.e. API keys, dynamic values based on configurations, API URLs), you can use Cypress environment variables.

The most common ways to pass environment variables to Cypress are the cypress.env.json file and the -e Cypress arg, which you can set in the project configuration or on the command line.

Create a cypress.env.json file in the projects root (i.e. apps/my-cool-app-e2e/cypress.env.json). Cypress will automatically pick up this file. This method is helpful for configurations that you don't want to commit. Make sure to add the file to the .gitignore and add documentation so people in your repo know what values to populate in their local copy of the cypress.env.json file.

Setting the -e Cypress arg in the project configuration is a good way to add values you want to define that you don't mind committing to the repository, such as a base API URL.

project.json
{
...
"targets": {
"e2e": {
"options": {
"args": "--env=API_URL=https://api.my-nx-website.com"
}
}
}
}

Finally, you can also pass environment variables via the command line with the -e Cypress arg.

Terminal window
nx e2e frontend-e2e -e=API_URL=https://api.my-nx-website.com,API_KEY=abc-123

Reading environment variables in tests on Cypress 16

Section titled “Reading environment variables in tests on Cypress 16”

Cypress 16 removed Cypress.env(). Cypress 13 to 15 keep it, so tests on those versions read env values synchronously as before. On Cypress 16, read env values with the asynchronous cy.env() command, which takes the list of keys to read:

cy.env(['API_URL']).then(({ API_URL }) => {
cy.request(`${API_URL}/health`);
});

For non-sensitive values that a test needs synchronously, use the Cypress 16 expose configuration (the expose config key, the --expose Cypress arg, or the expose test configuration) and read them with Cypress.expose('KEY'). The env values passed with --env are not readable with Cypress.expose().

In CI, Nx runs nx affected to rebuild and retest only the projects a change touches, and caches results to skip repeated work.

For a complete pipeline, see Set up CI.