Why Explicit Waiting Matters
Cypress commands are asynchronous and automatically retry many assertions, but a network request triggered by a click or page load doesn't block the test by default, which means the UI might not yet reflect the response when the next command runs. cy.wait('@alias') pauses the test until a request matching that alias's intercept has actually completed, giving you a reliable synchronization point instead of guessing with a fixed cy.wait(2000), which is both slower than necessary when the request is fast and flaky when the request is slow.
Cricket analogy: Waiting on a specific alias is like a scorer waiting for the actual ball to be bowled and its outcome confirmed before updating the scoreboard, rather than updating it after a fixed guessed number of seconds.
Waiting on Aliases and Response Assertions
cy.wait('@alias') returns a subject containing the full request and response cycle, which you can chain assertions onto, such as .its('response.statusCode').should('eq', 200) or .its('request.body').should('deep.include', { status: 'active' }). You can also pass an array of aliases like cy.wait(['@getUser', '@getSettings']) to wait for multiple requests fired in parallel, or add a custom timeout as a second argument, { timeout: 15000 }, when a particular endpoint is known to be slower than Cypress's default four-second command timeout.
Cricket analogy: Asserting on the waited response is like a match referee not just confirming the ball was bowled, but checking specifically whether it was called a no-ball, similar to checking response.statusCode after confirming the request happened.
cy.intercept('GET', '/api/user/settings').as('getSettings');
cy.intercept('GET', '/api/user/profile').as('getProfile');
cy.visit('/account');
// Wait for both parallel requests before asserting on the page
cy.wait(['@getProfile', '@getSettings']);
cy.wait('@getSettings', { timeout: 15000 })
.its('response.statusCode')
.should('eq', 200);
cy.wait('@getSettings')
.its('request.body')
.should('deep.include', { theme: 'dark' });
cy.get('[data-testid="settings-panel"]').should('be.visible');Waiting on the Same Alias Multiple Times
When the same endpoint is called more than once during a test, such as a search box that fires a new request on every keystroke, calling cy.wait('@search') repeatedly returns each successive matched call in order, first-in-first-out, so the first cy.wait() gets the first request and the next cy.wait() gets the second. You can also inspect the total number of matched calls with cy.get('@search.all') to assert on how many requests fired in total, which is useful for verifying debounce logic actually reduced network calls rather than firing one per keystroke.
Cricket analogy: Waiting on repeated calls to the same alias in order is like a scorer processing deliveries strictly ball by ball within an over, never skipping ahead to ball six before ball three has been recorded.
cy.get('@search.all') returns an array of every intercepted call matching that alias so far in the test, letting you assert cy.get('@search.all').should('have.length', 1) to confirm a debounced search input only fired a single network request despite multiple keystrokes.
Avoid using a bare cy.wait(milliseconds) with a hardcoded number as a substitute for cy.wait('@alias'). It either wastes time waiting longer than necessary on fast networks or produces flaky failures on slower CI runners where the real request takes longer than your guessed delay.
- cy.wait('@alias') pauses the test until a request matching that intercept alias completes, avoiding both flakiness and wasted time.
- The waited subject exposes request and response data for chained assertions like .its('response.statusCode').
- An array of aliases can be passed to cy.wait() to synchronize on multiple parallel requests at once.
- A custom { timeout } option overrides Cypress's default four-second command timeout for slower endpoints.
- Repeated calls to cy.wait('@alias') for the same alias return matched requests in first-in-first-out order.
- cy.get('@alias.all') returns every call matched so far, useful for asserting on debounce or call counts.
- Hardcoded cy.wait(ms) delays should be avoided in favor of alias-based waiting for reliability.
Practice what you learned
1. What does cy.wait('@alias') pause the test until?
2. How do you wait for two parallel requests, aliased @getUser and @getSettings, before proceeding?
3. If the same alias is used for a request fired three times, what order do successive cy.wait() calls resolve in?
4. What does cy.get('@search.all') return?
5. Why is a hardcoded cy.wait(2000) generally discouraged compared to cy.wait('@alias')?
Was this page helpful?
You May Also Like
Intercepting Network Requests with cy.intercept()
Learn how cy.intercept() lets Cypress observe, wait on, and control the XHR and fetch traffic your application sends during a test run.
Stubbing and Mocking API Responses
Learn how to replace real backend responses with controlled, static or dynamic data using cy.intercept() to test UI states reliably.
Testing API Endpoints Directly with cy.request()
Learn how cy.request() lets Cypress make direct HTTP calls outside the browser to set up state, verify APIs, and speed up tests.