Cypress Plugin (JavaScript)

The Cypress plugin enables users of the CypressNew tab JavaScript test framework to detect, manage, and quarantine flaky tests.

This page covers the following topics:

  1. Installation
  2. Running Cypress
    1. Command-line options
  3. Configuration
  4. Known caveats

LinkCompatibility

This plugin maintains compatibility with the following CypressNew tab and Node.jsNew tab versions:

Cypress Cypress
  • 13
  • 12
  • 11.2+
Node.js Node.js
  • 20
  • 18
  • 16

LinkInstallation

To install the Cypress plugin, add the @unflakable/cypress-plugin NPM package as a development dependency:

 yarn add --dev @unflakable/cypress-plugin
 npm install --save-dev @unflakable/cypress-plugin

LinkRunning Cypress

To run tests with the Cypress plugin, replace the cypress run commandNew tab with cypress-unflakable. This command automatically configures Cypress to use the plugin and invokes cypress run.

The plugin requires two configuration values:

  1. A test suite ID corresponding to an Unflakable test suiteNew tab. Be sure to add a test suite and select Cypress as the test framework before running tests using the plugin.
  2. An Unflakable API keyNew tab specified via the UNFLAKABLE_API_KEY environment variable.

To get started, run:

UNFLAKABLE_API_KEY=YOUR_API_KEY yarn exec \
  cypress-unflakable --test-suite-id YOUR_TEST_SUITE_ID
UNFLAKABLE_API_KEY=YOUR_API_KEY yarn exec -- \
  cypress-unflakable --test-suite-id YOUR_TEST_SUITE_ID
UNFLAKABLE_API_KEY=YOUR_API_KEY npm exec \
  --package=@unflakable/cypress-plugin \
  -c "cypress-unflakable --test-suite-id YOUR_TEST_SUITE_ID"

For convenience, we recommend adding a command to the scripts sectionNew tab of package.json. For example, use yarn test:ci or npm run test:ci (and set the UNFLAKABLE_API_KEY environment variable) to run the script configured in package.json below:

{
  ...
  "scripts": {
    "test:ci": "cypress-unflakable --test-suite-id YOUR_TEST_SUITE_ID"
  }
}

LinkCypress command-line options

The cypress-unflakable command supports the command-line options listed below, as well as any Cypress command-line optionsNew tab for cypress run. Use “--” to separate cypress-unflakable options (if any) from cypress run options. Any options after “--” will be passed directly to Cypress. For example, the following command runs Cypress component testsNew tab by passing the --component option to Cypress:

cypress-unflakable --test-suite-id YOUR_TEST_SUITE_ID -- --component

LinkPlugin command-line options

The cypress-unflakable command supports the following command-line options:

Link--[no-]auto-config

Default: --auto-config
By default, cypress-unflakable automatically wraps the Cypress configuration fileNew tab to register the plugin. Use --no-auto-config to disable this functionality and manually register the plugin in your Cypress configuration file instead.

Link--[no-]auto-support

Default: --auto-support

When the quarantine mode is set to skip_tests (via --quarantine-mode or the quarantineMode configuration option), the plugin automatically wraps the Cypress support fileNew tab to register the MochaNew tab instrumentation needed to skip any quarantined tests. Use --no-auto-support to disable this functionality and manually register the instrumentation in your Cypress support file instead.

If the quarantine mode is not skip_tests, this option has no effect.

Link--branch <string>

Default: Auto-detected from Git (unless --no-git-auto-detect is used or the gitAutoDetect configuration option is set to false)

Name of the version control (e.g., Git) branch containing the code being tested.

When test results are uploaded to Unflakable, the branch name is compared against the test suite's stable branches setting to determine whether to update the status of each test (e.g., flaky/quarantined) based on these test results, and whether to trigger notifications. Test results from unstable branches will be visible in the Unflakable web application but will not impact test statuses or trigger notifications.

Link--commit <string>

Default: Auto-detected from Git (unless --no-git-auto-detect is used or the gitAutoDetect configuration option is set to false)
Git commit hash (e.g., 8682b9e1d521a06e6b8df4eb4f0ff6ee2273f330) or other value that uniquely identifies the commit (version control revision) of the code being tested. This value helps identify test results in the Unflakable web application.

Link--failure-retries <integer>

Default: 2 (unless the failureRetries configuration option is set)

The maximum number of times to retry each failed test. To distinguish flaky tests from failing tests, the plugin retries each failed test until either it passes or this number of retries is exhausted. Note that the total number of attempts for each test is one greater than the number of retries, including the initial attempt.

Set this value to 0 to disable retries, which will also prevent any tests from automatically being marked as flaky.

Link--[no-]git-auto-detect

Default: --git-auto-detect
Whether the plugin should attempt to determine the current branch and commit hash from the GitNew tab repository containing the tests. If not using Git, or if auto-detection fails, consider passing --no-git-auto-detect and providing the optional but recommended --branch and --commit options.

Link--quarantine-mode <ignore_failures|no_quarantine|skip_tests>

Default: ignore_failures (unless the quarantineMode configuration option is set)

Controls the behavior of quarantined tests. The following values are supported:

  • ignore_failures: Quarantined tests run (including retries), but failures of quarantined tests do not cause the overall test suite to fail.
  • no_quarantine: Quarantined tests behave like all other tests. Failures will cause the test suite to fail.
  • skip_tests: Quarantined tests are skipped (do not run).

Link--test-suite-id <string>

Default: none (required unless the testSuiteId configuration option is set)
Unflakable test suiteNew tab for which the plugin should track and report test results.

Link--[no-]upload-results

Default: --upload-results (unless the uploadResults configuration option is set)
Whether to upload test results to Unflakable.

Link--help

Show help.

Link--version

Show version number.

LinkManual registration

By default, cypress-unflakable transparently wraps the Cypress configuration fileNew tab to register the plugin. It does so by passing the --config-fileNew tab option to cypress run with the path to the @unflakable/cypress-plugin/config-wrapper or @unflakable/cypress-plugin/config-wrapper-sync module. This option initially replaces the user-supplied Cypress configuration (e.g., cypress.config.js). After the wrapper module loads, it also loads the user-supplied Cypress configuration. In most cases, this process is transparent and should respect all of the user-supplied configuration values, including running the setupNodeEventsNew tab function.

For advanced use cases that conflict with the automatic configuration process, the plugin can be registered manually instead. To do so, pass the --no-auto-config option to cypress-unflakable and define a setupNodeEventsNew tab function in your Cypress configuration file that calls the registerUnflakable() function and returns its return value. We also recommend using the cypress-on-fixNew tab package, which works around a known Cypress issueNew tab to keep multiple Cypress plugins from conflicting:

const { registerUnflakable } = require("@unflakable/cypress-plugin");
const cypressOnFix = require("cypress-on-fix");

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // e2e testing node events setup code
      ...

      return registerUnflakable(on, config);
    },
  },
  component: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // component testing node events setup code
      ...

      return registerUnflakable(on, config);
    },
  },
});
import { registerUnflakable } from "@unflakable/cypress-plugin";
import cypressOnFix from "cypress-on-fix";

export default defineConfig({
  e2e: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // e2e testing node events setup code
      ...

      return registerUnflakable(on, config);
    },
  },
  component: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // component testing node events setup code
      ...

      return registerUnflakable(on, config);
    },
  },
});

Please also let us know about your use case by contacting SupportNew tab or filing a GitHub issueNew tab so that we can help make the Cypress plugin work transparently for as many scenarios as possible.

LinkSupport file

When the quarantine mode is set to skip_tests (via --quarantine-mode or the quarantineMode configuration option), the plugin transparently wraps the Cypress support fileNew tab to register the MochaNew tab instrumentation needed to skip any quarantined tests. It does so by generating a temporary support file that loads both the Unflakable Mocha instrumentation and the existing user support file (if any).

For advanced use cases that conflict with this process, the Mocha instrumentation can be registered manually instead by passing the --no-auto-support option to cypress-unflakable and adding the following code to your Cypress support fileNew tab:

const {
  registerMochaInstrumentation,
} = require("@unflakable/cypress-plugin/skip-tests");
...

registerMochaInstrumentation();
import { registerMochaInstrumentation } from "@unflakable/cypress-plugin/skip-tests";
...

registerMochaInstrumentation();

When manually registering both the plugin (see above) and the Mocha instrumentation, pass the autoSupportFile: false option to registerUnflakable in the Cypress configuration fileNew tab instead of passing the --no-auto-support option to cypress-unflakable (which has no effect when --no-auto-config is passed):

const { registerUnflakable } = require("@unflakable/cypress-plugin");
const cypressOnFix = require("cypress-on-fix");

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // e2e testing node events setup code
      ...

      return registerUnflakable(on, config, { autoSupportFile: false });
    },
  },
  component: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // component testing node events setup code
      ...

      return registerUnflakable(on, config, { autoSupportFile: false });
    },
  },
});
import { registerUnflakable } from "@unflakable/cypress-plugin";
import cypressOnFix from "cypress-on-fix";

export default defineConfig({
  e2e: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // e2e testing node events setup code
      ...

      return registerUnflakable(on, config, { autoSupportFile: false });
    },
  },
  component: {
    setupNodeEvents(baseOn, config) {
      // Work around https://github.com/cypress-io/cypress/issues/22428 to prevent
      // multiple plugins from conflicting.
      const on = cypressOnFix(baseOn);

      // component testing node events setup code
      ...

      return registerUnflakable(on, config, { autoSupportFile: false });
    },
  },
});

Please also let us know about your use case by contacting SupportNew tab or filing a GitHub issueNew tab so that we can help make the Cypress plugin work transparently for as many scenarios as possible.

LinkConfiguration

Many of the plugin's command-line options can instead be stored in a configuration file. Depending on your preference, specify the test suite ID and any desired configuration options in package.json or a separate file named unflakable.json (JSON), unflakable.js/unflakable.cjs (JavaScript), or unflakable.yml/unflakable.yaml (YAML). Save the file to the directory containing your Cypress configuration fileNew tab (e.g., cypress.config.js or cypress.config.ts) or one of its ancestors, and commit it to your code repository.

Alternatively, the test suite ID may be specified at runtime via the UNFLAKABLE_SUITE_ID environment variable or --test-suite-id command-line option. We recommend using the command-line option or environment variable if you run more than one Unflakable test suite in the same repository and would like to share common configuration options between the test suites.

{
  ...
  "unflakable": {
    "testSuiteId": "YOUR_TEST_SUITE_ID"
  },
  ...
}
{
  "testSuiteId": "YOUR_TEST_SUITE_ID"
}
module.exports = {
  testSuiteId: "YOUR_TEST_SUITE_ID",
}
testSuiteId: YOUR_TEST_SUITE_ID

LinkConfiguration options

The Cypress plugin supports the configuration options below. Environment variables appear in parentheses for options that may be specified either as command-line options, in the configuration file, or as environment variables. Command-line options take precedence over environment variables, which take precedence over configuration files.

LinkfailureRetries integer

Default: 2

The maximum number of times to retry each failed test. To distinguish flaky tests from failing tests, the plugin retries each failed test until either it passes or this number of retries is exhausted. Note that the total number of attempts for each test is one greater than the number of retries, including the initial attempt.

Set this value to 0 to disable retries, which will also prevent any tests from automatically being marked as flaky.

LinkgitAutoDetect boolean

Default: true
Whether the plugin should attempt to determine the current branch and commit hash from the GitNew tab repository containing the tests. If not using Git, or if auto-detection fails, consider setting this to false and providing the optional but recommended UNFLAKABLE_BRANCH and UNFLAKABLE_COMMIT environment variables.

LinkquarantineMode enum

Default: ignore_failures

Controls the behavior of quarantined tests. The following values are supported:

  • ignore_failures: Quarantined tests run (including retries), but failures of quarantined tests do not cause the overall test suite to fail.
  • no_quarantine: Quarantined tests behave like all other tests. Failures will cause the test suite to fail.
  • skip_tests: Quarantined tests are skipped (do not run).

LinktestSuiteId (UNFLAKABLE_SUITE_ID) string

Default: none (required)
Unflakable test suiteNew tab for which the plugin should track and report test results. If using the same plugin configuration file for multiple test suites, we recommend setting the UNFLAKABLE_SUITE_ID environment variable instead of setting testSuiteId in the configuration file.

LinkuploadResults (UNFLAKABLE_UPLOAD_RESULTS) boolean

Default: true
Whether to report test results to Unflakable. If set to false, quarantined tests continue to behave as specified by quarantineMode, but test results will not be reported to Unflakable and failures will not cause tests to be marked as flaky or trigger notifications.

LinkUNFLAKABLE_API_KEY (environment variable only)string

Default: none (required)
Secret API keyNew tab used to authenticate to Unflakable for determining which tests are quarantined and for reporting test results.

LinkUNFLAKABLE_BRANCH (environment variable only)string

Default: Auto-detected from Git (unless gitAutoDetect is false)

Name of the version control (e.g., Git) branch containing the code being tested.

When test results are uploaded to Unflakable, the branch name is compared against the test suite's stable branches setting to determine whether to update the status of each test (e.g., flaky/quarantined) based on these test results, and whether to trigger notifications. Test results from unstable branches will be visible in the Unflakable web application but will not impact test statuses or trigger notifications.

LinkUNFLAKABLE_COMMIT (environment variable only)string

Default: Auto-detected from Git (unless gitAutoDetect is false)
Git commit hash (e.g., 8682b9e1d521a06e6b8df4eb4f0ff6ee2273f330) or other value that uniquely identifies the commit (version control revision) of the code being tested. This value helps identify test results in the Unflakable web application.

LinkKnown caveats

This section documents important caveats about how the Unflakable Cypress plugin interacts with Cypress.

LinkCypress retries

The plugin leverages Cypress's built-in support for test retriesNew tab in order to distinguish flaky tests from failing tests (see the --failure-retries command-line option or failureRetries configuration option).

Ordinarily, Cypress treats tests that pass during a retry as passes, which hides flaky tests. For example, if a test fails twice and then passes on the third attempt, Cypress considers the test to have passed. By contrast, the Unflakable Cypress plugin treats tests that pass during retry as flaky, and cypress-unflakable will exit with a failing (non-zero) exit code if any non-quarantined tests exhibited flakiness during a Cypress run.

LinkMocha before/after hooks

Both Cypress and the Unflakable Cypress plugin treat Mocha beforeEach and afterEach hooksNew tab effectively as part of the test they immediately precede/follow, respectively. If either the test or one of these hooks fails, both the test and any associated beforeEach/afterEach hooks will be retried. If a test is quarantined, failures in its beforeEach/afterEach hooks will be handled as if the test itself had failed, according to the configured --quarantine-mode.

Cypress treats before and after hooks, which run only once per spec file or describe() block, differently from beforeEach/afterEach hooks. When one of these hooks fails, Cypress does not retry the hook or any of the tests that depend on it. It also skips any remaining tests that depend on a failed before hook. Because the Unflakable Cypress plugin depends on Cypress for test retries, it is unable to detect flakiness associated with before and after hooks. Instead, a failed before hook will be treated as if the first test (which will be skipped) had failed, and a failed after hook will be treated as if the last test to run had failed.

LinkMocha reporters

Cypress allows users to configure built-in or custom Mocha reportersNew tab. These reporters emit test results in a variety of output formats (e.g., human-friendly terminal output, HTML, etc.). The Unflakable Cypress plugin replaces the default spec reporterNew tab with a modified version that supports flaky and quarantined tests, along with improved output for retried tests.

The plugin will load any configured non-default Mocha reporters, which will continue to receive test results. However, other reporters will not distinguish between flaky and failed tests, nor will they support quarantining of failures. Consequently, other reporters may report that a test has failed, while the plugin's terminal output may show that a test was flaky and/or quarantined.

LinkCypress Cloud

The Unflakable Cypress plugin is currently incompatible with Cypress CloudNew tab.