How Cypress Automatic Waiting Reduces UI Test Flakiness
Learn how Cypress’s automatic waiting and retry mechanism eliminates flaky UI tests, with a concrete example, timeout tuning tips, and practical verification steps.
31 Jul 2026, 01:27 UTC

Problem: Flaky UI Tests Due to Timing
When a test interacts with elements that appear after an API call, animation, or lazy‑load, the element may not be present the first time the test runs. A hard‑coded cy.wait can mask the real cause and makes tests brittle.
How Automatic Waiting Works
Cypress commands such as cy.get, cy.contains, and cy.find are built to retry until they succeed or a timeout expires. Assertions chained with .should or .expect are re‑evaluated on each retry. This means the test framework continuously polls the DOM and the application state without any explicit wait code from you.
Worked Example: Button Appears After an API Call
Consider a page where a submit button is rendered only after a successful login request.
// cypress/integration/login_spec.js
describe('Login flow', () => {
it('shows the submit button after credentials are valid', () => {
// Visit the login page
cy.visit('https://example.com/login')
// Fill in the form
cy.get('#username').type('test_user')
cy.get('#password').type('secure_pass{enter}')
// The button appears after the login request finishes
// No cy.wait needed – Cypress will retry get and the assertion
cy.get('#submit-button').should('be.visible')
// Proceed with the test
cy.get('#submit-button').click()
cy.url().should('include', '/dashboard')
})
})
When you run this test (npx cypress open), open the Command Log. You will see cy.get('#submit-button') attempted multiple times, each followed by the .should('be.visible') assertion, until the button is present or the timeout expires.
Trade‑off: Timeout Length and Test Speed
The default timeout for most Cypress commands is 4000 ms. If your application is genuinely slow, a high timeout can hide performance regressions because the test will still pass, just slower. Conversely, setting the timeout too low causes legitimate delays to produce false failures.
You can adjust the global default in cypress.json:
{
"defaultCommandTimeout": 2500
}
After changing this value, re‑run the same test. If the button takes longer than 2500 ms to appear, the test will fail faster, giving you immediate feedback about a performance issue.
Actionable Guidance
- Rely on Cypress’s built‑in retry for UI interactions; avoid manual
cy.waitunless you are waiting for a non‑DOM condition (e.g., a network stub). - Use
cy.interceptto stub slow backend responses during testing, then let Cypress wait for the UI to update. - Monitor test duration in the Cypress Test Runner or CI logs. If tests consistently run near the timeout, investigate whether the application is slow or the timeout is too low.
- When you need to verify that a timeout is working as intended, deliberately delay an element (e.g., with
cy.wait(3000)in the application code) and observe whether the test passes or fails after adjustingdefaultCommandTimeout.
By trusting Cypress’s automatic waiting and tuning timeouts to match realistic performance expectations, you obtain faster feedback and more reliable UI tests without sprinkling arbitrary waits throughout your test suite.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.