In Cypress, what do retries.runMode and retries.openMode control, and what are their defaults?
answer
- Retrying is not on out of the box
- Two modes, two separate counts
- The number is not the total
- CI and the interactive App differ here
- Attempt zero is still an attempt
basics
~20 sThey set how many extra attempts Cypress gives a failing test: runMode applies to cypress run, openMode to cypress open. Both default to 0, so an unconfigured suite never retries a failing test at all.
solid answer
~40 s`retries` is a Cypress configuration option that takes either a number or an object with `runMode` and `openMode`. Each value is a count of *additional* attempts, not the total, so `runMode: 2` allows up to three executions of a failing test under `cypress run`. Both default to `0`, which is why a suite that has never been configured reports the first failure and moves on. The two modes are separate because retrying pays off very differently: in CI it stops one intermittent test from blocking a pipeline, while in the interactive App a human is already watching, so most teams set `runMode` to 1 or 2 and leave `openMode` at 0. Only failures start a retry, and the last attempt decides the reported result.
go deeper
Recall the shape of the option and its default: an object with runMode and openMode, both 0, counting extra attempts on top of the first run.
Be ready to explain what a single attempt repeats - the test body with its beforeEach and afterEach hooks - and why suite-level hooks are outside that boundary.
Expect to justify the number you picked for a real pipeline, and to say what evidence you would keep so a retried failure is still investigated rather than forgotten.
Own the standard: who is allowed to raise the count, what has to be true before a test is retried at all, and how the team avoids treating retries as a permanent fix.
## What the `retries` option counts Cypress ships with test retries switched **off**. As of Cypress 16 the `retries` configuration option defaults to `{ runMode: 0, openMode: 0 }`: a failing test runs exactly once, is reported failed, and the run continues. When you do set it, the number is a count of **extra attempts**, never the total number of executions. - `retries: 2` — up to three executions of a failing test (the original attempt plus two retries), in both modes. - `retries: { runMode: 2, openMode: 0 }` — up to three executions under `cypress run`, exactly one under `cypress open`. - A **passing** test is never re-executed; only a failure starts a retry. - The **last** attempt decides the reported outcome. A test that fails twice and passes on the third attempt is reported as passed. ## Why `runMode` and `openMode` are separate keys `runMode` covers `cypress run`, the non-interactive execution CI drives. `openMode` covers `cypress open`, the interactive App you debug in. They are separate keys because a retry is worth very different amounts in the two places. | | `runMode` | `openMode` | |---|---|---| | Applies to | `cypress run` | `cypress open` | | Default | `0` | `0` | | Usual setting | `1` or `2` | `0` | | What a retry buys | a pipeline not blocked by one intermittent test | little — someone is already watching | | What a retry costs | wall-clock time and a weaker failure signal | several attempts to scroll back through | Because `retries` is one of the options that can be overridden per suite and per test, a single badly-behaved specification can be given its own count without loosening the whole project. ## What one attempt actually repeats An attempt is a fresh execution of the **test**, not of the spec file: 1. The Mocha `beforeEach` hooks that apply to the test, in declaration order. 2. The `it` body, from its first `cy` command. 3. The Mocha `afterEach` hooks, once the attempt ends. Mocha's `before` and `after` hooks are **not** repeated — they belong to the suite, not to the test — and a failure *inside* `before` or `after` does not trigger a retry at all. Cypress resets the browser between attempts the way it does between tests, but nothing outside the browser is rewound: whatever the failed attempt wrote to your backend is still there for the next one. ## Reading and recognising an attempt `Cypress.currentRetry` is a number readable inside a test or a test hook: `0` on the first execution, `1` on the first retry, and so on. It is `null` outside a test or hook, so it is not something to reach for in a plugin or at the top of a spec file. Failure artefacts are labelled as well — a screenshot taken on the second attempt gains an `(attempt 2)` suffix in its filename, so a folder of screenshots tells you which execution produced which image. ## Test retries are not the same mechanism as retry-ability Two different things get called "retrying", and the option only controls the second: - **Retry-ability** happens *inside* a test. Cypress re-runs linked queries and their assertions for up to `defaultCommandTimeout` so that a late render does not fail an assertion. It is on by default and it costs milliseconds. - **Test retries** happen *after* a test has already failed. Cypress re-executes the whole test from its first command. It is off by default and it costs a full test's worth of wall-clock time. The second is a far blunter instrument than the first, and it only begins where the first has already given up. When a failure gets absorbed by a test retry, the useful question is usually why the assertion inside the test could not retry its way to a pass — not how many test-level attempts to allow. ## What the option cannot decide for you Setting a count is easy; the consequences are the interesting part. - A retry does not remove a failure, it removes its **visibility** at the top level of the report. - The higher `runMode` climbs, the more reliably a genuinely broken test goes green, and that is exactly the test you most needed to see fail. - `openMode: 0` is the useful default precisely because you want a failure to sit still on screen while you look at it. - A retry can only cure a failure whose cause was transient and inside the browser — a render that arrived late, a response that was slow. A wrong selector, a real regression, or an effect the first attempt already committed fails identically on every attempt.
- If retries is set to a plain number instead of an object, what happens?The single number is applied to both modes, so `retries: 1` gives a failing test one extra attempt in `cypress run` and one in `cypress open`. The object form exists so you can keep the interactive count at 0 while CI retries.
- Does a retry re-run the whole spec file or just the failed test?Just the failed test, together with the Mocha `beforeEach` and `afterEach` hooks that apply to it. Other tests in the spec are untouched, and suite-level `before`/`after` hooks run once for the suite regardless of how many attempts a test takes.
saying these in an interview costs you the question
- Thinks Cypress retries failing tests by default
- Reads runMode: 2 as two total executions rather than three
- Believes a retry re-runs the whole spec file
- Sets the same high count for openMode and runMode without thinking
- Assumes a failing before hook is retried like a test