Mastering Cypress.io Interception: Stub, Spy, and Validate API Calls
Learn how to replace real backend calls with controlled stubs in Cypress, ensuring fast, deterministic tests. Follow this step‑by‑step guide to set up cy.intercept, validate requests, and handle failures.
11 Mar 2026, 18:23 UTC

Desired Outcome
Replace real backend calls with controlled stubs so that end‑to‑end tests run fast, deterministically, and independently of the server. By stubbing or spying on network requests you can:
- Simulate success, error, and latency scenarios.
- Validate that the UI sends the correct payload.
- Prevent flaky tests caused by network variability.
Prerequisites
- Cypress v6.0+ (cy.intercept replaces cy.route).
- A running Cypress test suite (E2E or Component).
- Knowledge of the API endpoints your app calls – URLs, HTTP methods, and expected request/response shapes.
- Optional: fixture files placed in
cypress/fixturesfor static responses.
Step‑by‑Step Procedure
- Identify the Target Call
- Open
npx cypress openand run the test that triggers the request. - In the Cypress DevTools Routes panel, locate the matching network request.
- Copy its
URLandmethodfor the intercept pattern.
- Open
- Write the Intercept
Place the
cy.intercept()command before the user action that triggers the request. The command can be insidebeforeEach()or directly in theit()block.// Example: GET /api/users cy.intercept({ method: 'GET', url: '/api/users', }, { statusCode: 200, body: { users: [{ id: 1, name: 'Alice' }] }, headers: { 'x-test-header': '123' }, delayMs: 200, // simulate latency }).as('getUsers');Use a fixture for a larger payload:
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers'); - Trigger the Request
Perform the UI action that causes the request, e.g., clicking a button that loads users.
cy.get('#load-users').click(); - Wait and Assert the Intercept
Use
cy.wait('@alias')to capture the request/response object.cy.wait('@getUsers').then((interception) => { // Verify request details expect(interception.request.method).to.equal('GET'); expect(interception.request.url).to.include('/api/users'); // Verify response expect(interception.response.statusCode).to.equal(200); expect(interception.response.body).to.have.property('users'); });After the wait, validate UI changes that depend on the stubbed data.
cy.get('.user-list').should('contain', 'Alice'); - Spying Without Stubbing
If you want to let the request hit the real server but still capture its details, omit the response object:
cy.intercept('GET', '/api/users').as('getUsersLive');Then you can assert the request body or headers after
cy.wait('@getUsersLive'). - Advanced: GraphQL Stubbing
GraphQL endpoints are usually a single POST. Match the URL and filter by
operationNameor query string.cy.intercept('POST', '/graphql', (req) => { if (req.body.operationName === 'GetUsers') { req.reply({ data: { users: [{ id: 1, name: 'Alice' }] } }); } }); - Handling Edge Cases
- Simulate errors:
statusCode: 500orforceNetworkError: true. - Delay:
delayMs: 5000to test loading states. - Dynamic responses: use a callback that reads a fixture or computes a value.
- Simulate errors:
Validating the Stub
After the test runs, confirm that interception happened:
- In headed mode, the Routes panel shows the alias and the response status.
- Use
cy.log(JSON.stringify(interception))inside thethen()to inspect the captured object. - Verify that no unhandled network errors appear in the command log.
Common Pitfalls & Recovery Options
| Issue | Cause | Fix |
|---|---|---|
| Intercept never matches | Trailing slash or query string differences | Use a glob pattern (e.g., /api/users*) or RegExp. |
| Cached response bypasses intercept | Browser caching enabled | Disable caching in Cypress config: chromeWebSecurity: false or add Cache-Control: no-store header to the request. |
| Stubbing hides integration bugs | All critical API calls mocked | Keep a handful of unmocked tests with cy.intercept({ middleware: true }) to log traffic. |
| Aliases reset between tests | Declared in before() instead of beforeEach() | Move intercepts into beforeEach() or declare inside each it(). |
| Proxying in component tests changes path | Dev server rewrites /api to localhost:3000/api | Match the full URL: http://localhost:3000/api/**. |
Advanced Use Cases
- Conditional Stubs – Return different responses based on request body or headers.
- Multiple Intercepts – Chain
cy.intercept()calls for sequential API calls. - Logging Middleware –
cy.intercept({ middleware: true })to log all traffic without altering it.
Summary
Using cy.intercept() you can fully control network interactions in Cypress tests. Define clear stubs for success, error, and delay scenarios; spy on real traffic when needed; and validate both request payloads and UI responses. By following the steps above and watching for common pitfalls, your test suite will become faster, more reliable, and easier to maintain.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.