How to Mock Network Requests in Cypress: A Complete Guide to cy.intercept()

Use cy.intercept() to mock network requests in Cypress by registering route matchers that return static responses, fixtures, or dynamic replies, enabling reliable API stubbing without modifying application code.

Cypress provides a powerful network-stubbing API through the cy.intercept() command, implemented in the net-stubbing package of the cypress-io/cypress monorepo. Understanding how to mock network requests in Cypress requires familiarity with the command's architecture, which spans from driver-side validation to server-side request interception. This guide covers the complete implementation path, from matcher registration to response generation, using the actual source code structure.

The Architecture Behind cy.intercept()

The cy.intercept() command operates through a coordinated system between the Cypress driver and a dedicated server-side net-stubbing layer. When you call cy.intercept(), the command registration occurs in packages/driver/src/cy/net-stubbing/add-command.ts, which validates your matcher, creates a unique route ID, and emits a route:added net-event to the server.

Matcher Normalization and Validation

Before a route becomes active, the driver normalizes your matcher options. In add-command.ts, the helper function annotateMatcherOptionsTypes converts non-primitive types like RegExp into serializable formats that can traverse the driver-server boundary. HTTP header names are normalized to lowercase (lines 4-8) to ensure case-insensitive matching according to HTTP specifications.

Static Response Processing

When you provide a static response (JSON objects, strings, or fixtures), the driver validates these options through validateStaticResponse in packages/driver/src/cy/net-stubbing/static-response-utils.ts. This function enforces mutually exclusive rules—such as preventing simultaneous body and fixture usage—while getBackendStaticResponse transforms your configuration into a server-compatible format with correct MIME types and throttling parameters.

Server-Side Request Interception

The server component resides in packages/net-stubbing/lib/server/. When the route:added event arrives, the DriverInterceptRegistrationAdapter registers a request interceptor that monitors every HTTP request from the Application Under Test (AUT). The matching logic in handle-intercept-request.ts determines whether to forward the request to the original destination or serve a stubbed response based on your registered routes.

Basic Request Mocking with Static JSON

The most common approach to mock network requests in Cypress involves returning a static payload for a specific URL pattern. The driver sends this configuration through validateStaticResponse before the server applies it.

// Intercept any GET request to /api/users and return a custom payload
cy.intercept('GET', '/api/users', {
  statusCode: 200,
  body: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }],
}).as('getUsers')

// Trigger the request in your app
cy.get('button.load-users').click()

// Wait for the stubbed request and assert the UI
cy.wait('@getUsers')
cy.get('.user-list').should('contain', 'Alice')

Mocking with Fixture Files

For larger response payloads, store data in the cypress/fixtures directory and reference them using the fixture key. The STATIC_RESPONSE_KEYS definition includes fixture support, and getFixtureOpts resolves the file path on the server side.

// Serve a fixture located at cypress/fixtures/users.json
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('usersFixture')
cy.wait('@usersFixture')

Simulating Network Latency and Throttling

You can test how your application handles slow networks by adding artificial delays or bandwidth constraints. These values pass through validateStaticResponse (lines 52-58) and are enforced by the server when constructing the response stream.

cy.intercept('GET', '/slow-endpoint', {
  delay: 2000,          // 2-second artificial latency
  throttleKbps: 50,     // limit bandwidth to 50 kbps
  body: 'slow response',
}).as('slow')

Dynamic Request Handling with Route Handlers

For conditional logic or request modification, provide a function as the second argument. When add-command.ts detects a function handler (line 81), it sets hasInterceptor = true and registers a request interceptor that forwards the request to your callback, allowing you to inspect, modify, or abort the request programmatically.

cy.intercept(
  { method: 'POST', url: '/api/login' },
  (req) => {
    // inspect or modify the request before it goes to the server
    if (req.body.username === 'admin') {
      req.reply({ statusCode: 403, body: 'Forbidden' })
    } else {
      req.continue()
    }
  }
).as('login')

Matching Requests by Headers

To mock network requests based on specific headers, include a headers object in your matcher. The driver automatically lowercases header names during normalization to ensure reliable matching regardless of casing.

cy.intercept({
  method: 'GET',
  url: '/api/data',
  headers: { 'x-custom-header': 'my-value' }
}, { body: 'ok' })

Key Implementation Files

Understanding these source files helps debug complex stubbing scenarios:

Summary

  • Mock network requests in Cypress using cy.intercept(), which replaces the deprecated cy.route() with a more flexible API.
  • The command implementation spans packages/driver/src/cy/net-stubbing/add-command.ts for validation and packages/net-stubbing/lib/server/ for execution.
  • Static responses are validated by validateStaticResponse and transformed by getBackendStaticResponse before reaching the server.
  • Dynamic handling uses function interceptors set via hasInterceptor = true in the route registration logic.
  • Header matching is case-insensitive due to normalization in the driver layer.
  • Network conditions like delay and throttleKbps are applied server-side after passing through static response validation.

Frequently Asked Questions

What is the difference between cy.intercept() and cy.route() in Cypress?

cy.intercept() is the modern replacement for cy.route() that uses the net-stubbing architecture instead of the legacy cy.server() mechanism. According to the cypress-io/cypress source code, cy.intercept() operates at the network layer rather than the XMLHttpRequest layer, allowing it to stub fetch requests, WebSockets, and other HTTP traffic that cy.route() cannot capture. The new API also supports route matching with glob patterns, RegExp, and headers without requiring cy.server() to be initialized first.

How do I mock network requests with dynamic responses based on request data?

Provide a route handler function as the second argument to cy.intercept(). When the driver detects a function in add-command.ts, it sets hasInterceptor = true and registers a request interceptor that invokes your function with a req object. You can inspect req.body, req.headers, or req.url, then call req.reply() to send a custom response or req.continue() to pass the request to the original server. This pattern is implemented in the server-side logic where DriverInterceptRegistrationAdapter forwards matched requests to your handler.

Can I delay or throttle responses when mocking network requests in Cypress?

Yes, include delay (milliseconds) or throttleKbps (kilobits per second) in your static response object. These values are validated by validateStaticResponse in static-response-utils.ts and enforced by the server when streaming the response back to the browser. This allows you to simulate slow 3G connections or server latency by adding delay: 2000 or throttleKbps: 50 to your cy.intercept() configuration.

How does Cypress handle case-insensitive header matching?

The driver normalizes all header names to lowercase in add-command.ts (lines 4-8) before sending the matcher to the server. This ensures that headers: { 'X-Custom-Header': 'value' } matches requests containing x-custom-header or X-CUSTOM-HEADER, adhering to HTTP specification requirements for case-insensitive header names. When you provide a headers matcher object, the comparison occurs after this normalization on both the matcher and the incoming request headers.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →