Automatic retrying is the mechanism underneath Cypress's waiting philosophy. This lesson explains exactly how it works, which commands participate, and how to reason about retry timing.
How Retrying Actually Works
When you chain a query with an assertion, cy.get(selector).should(assertion), Cypress does not run cy.get() once and then check the assertion once. Instead, it repeats the entire chain: re-query the DOM, re-check the assertion, repeatedly, until the assertion passes or the timeout is reached.
This retry loop happens quickly (checking many times per second) and stops the instant the assertion succeeds, so a passing test does not incur any unnecessary delay, it resolves as soon as the real condition becomes true.
cy.get('[data-cy="notification"]').should('have.text', 'Saved!');
// Internally: re-run cy.get() + check the assertion,
// repeatedly, until it passes or defaultCommandTimeout elapses.
If the notification appears after 400ms, the assertion resolves at roughly that point, not at some fixed later time.
What Gets Retried
cy.get(selector).should(...) // retried: query + assertion
cy.contains(text).should(...) // retried: query + assertion
cy.get(selector).click() // waits for actionability, once found
cy.request(...) // NOT retried, runs once
Query commands followed by an assertion are retried as a unit.
Action commands wait for actionability but do not retry the action itself repeatedly.
cy.request(), cy.exec(), and similar one-shot commands are never automatically retried.
Retrying stops immediately once the assertion passes, it does not always run for the full timeout.
Retry Behavior Cheat Sheet
Quick reference for which command categories participate in automatic retrying.
Command
Retried?
Notes
cy.get() + .should()
Yes
Full chain re-run on each attempt
cy.contains() + .should()
Yes
Same retry behavior as cy.get()
.click(), .type()
Partially
Waits for actionability, not repeated action
cy.request()
No
Single HTTP request, runs once
cy.exec()
No
Single shell command execution
cy.wait('@alias')
Yes (for the wait itself)
Waits for the aliased request/response
A Concrete Retry Loop Example
Imagine a button click triggers an API call, and only after the response arrives does a success message appear. Cypress's retry loop naturally accommodates this without any special handling from you.
cy.get('[data-cy="save"]').click();
// Cypress retries the following until it passes:
cy.get('[data-cy="success-message"]')
.should('be.visible')
.and('contain', 'Changes saved');
Whether the API responds in 100ms or 2 seconds, this assertion resolves as soon as the message actually appears.
Retrying Negative Assertions Correctly
Negative assertions like should('not.exist') are retried the same way: Cypress keeps re-checking until the element is actually gone, correctly waiting through the moment where it might still be mid-removal (like a fade-out animation).
Assuming a command's failure means it failed on the first attempt, when it may have retried for the full timeout duration first.
Expecting cy.request() or cy.exec() to retry like query/assertion chains do.
Writing a .should(callback) with a side effect (like a click), which can run multiple times during retries.
Not realizing negative assertions (not.exist, not.be.visible) benefit from the exact same retry mechanism as positive ones.
Key Takeaways
Retrying re-runs the entire query/assertion chain repeatedly, not just the final check.
Retrying resolves immediately once the assertion passes, incurring no unnecessary delay on success.
Not all commands are retried, one-shot commands like cy.request() run exactly once.
Negative assertions use the same retry mechanism as positive ones, correctly waiting for removal/absence.
Pro Tip
Never put a side-effecting action (like a click or a network request) inside a .should(callback), since a retry can invoke that callback multiple times, silently triggering the side effect repeatedly and producing confusing, hard-to-debug test behavior.
You now understand exactly how automatic retrying works. Next, learn how to configure and reason about Timeouts.