Harnessing Cypress.io’s Built‑In Retry‑Ability for Stable Tests
Learn how Cypress.io’s built‑in retry‑ability reduces flakiness, when it can hide bugs, and how to validate it in real projects with practical examples.
26 Sept 2025, 17:28 UTC

The Problem: Test Flakiness from Transient UI Changes
When a test clicks a button that appears after an AJAX call or a timeout, a plain cy.get('button') can fail if the element isn’t rendered yet. The test suite may intermittently pass or fail, making it hard to trust results. Traditional solutions add explicit cy.wait calls, which increase test duration and still don’t guarantee stability.
How Cypress Handles Retries
Cypress automatically retries every command that returns a Chainable (the object that lets you chain further commands) until the command succeeds or a timeout is reached. The default timeout is 4 seconds for most commands, configurable with Cypress.config('defaultCommandTimeout', value). Assertions like expect() are evaluated only after the command succeeds, so they inherit the retry logic.
Key points:
- Retries are scoped to the command chain; a failed assertion does not trigger a retry of the preceding command.
- Only commands that return a chainable are retried. Plain JavaScript or native promises bypass the retry mechanism.
- Custom commands that return chainables work seamlessly; those that return plain objects or use
async/awaitdo not.
Practical Usage Patterns
Below is a concrete example that demonstrates how the retry‑ability works in a real test. The application renders a Start button after a 2‑second delay. The test clicks the button without any explicit waits.
// cypress/integration/button_retries_spec.js
describe('Retry‑ability demo', () => {
it('clicks the button that appears after a delay', () => {
cy.visit('/delayed-button');
// The button is rendered after 2000ms, but Cypress will keep retrying
// until it exists or the timeout is hit.
cy.get('button[data-test=\'start\']')
.should('be.visible')
.click();
// Verify the next step
cy.contains('You started!').should('exist');
});
});
Running this test with the default timeout of 4 seconds will always pass, because the button appears within 2 seconds. If you reduce the timeout to 1 second, the test will fail, confirming that the timeout governs the retry duration.
// cypress/support/commands.js
Cypress.config('defaultCommandTimeout', 1000); // 1 second
Because the command chain retries until the button exists, you avoid hard‑coded cy.wait calls while keeping the test fast and deterministic.
When Retries Mask Real Bugs
Retry‑ability can hide subtle UI issues:
- If the application’s state never reaches the expected condition but the timeout is high, the test may pass after the timeout, giving a false sense of correctness.
- Custom commands that return plain objects (e.g.,
Cypress.Commands.add('getUser', () => fetch('/api').then(r => r.json()));) do not trigger retries. If the underlying data changes asynchronously, the test may incorrectly pass or fail.
To mitigate these risks:
- Keep
defaultCommandTimeoutreasonable (e.g., 4 seconds) and only increase it for genuinely slow operations. - Wrap non‑chainable async work with
cy.wrapso it becomes retriable. - Add explicit assertions that verify the final application state, not just the presence of an element.
Validating Retry‑Ability in Your Project
Here’s a quick checklist you can run locally:
- Write a test that interacts with a UI element that appears after a short delay.
- Run the test with the default timeout; it should pass.
- Reduce
defaultCommandTimeoutto a value below the delay; the test should fail. - Introduce a custom command that returns a plain object; confirm that it does not retry.
By following these steps you can confirm that Cypress’s retry‑ability behaves as expected in your codebase.
Conclusion
Built‑in retry‑ability is a powerful feature that eliminates the need for manual waits and reduces test flakiness. Use it judiciously: keep timeouts sensible, wrap async work in chainables, and always assert the final state of the application. With these practices, Cypress tests become faster, more reliable, and easier to maintain.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.