Cypress Intercept

Cypress Intercept allows you to monitor and modify network requests and responses within your Cypress tests. It's useful for stubbing API calls, mocking data, and testing edge cases without relying on a live backend.

Detailed explanation

Cypress intercept is a powerful command that allows you to control and manipulate network requests made by your application during testing. This capability is crucial for isolating your frontend tests, simulating various server responses, and testing how your application handles different scenarios without depending on a real backend. It provides a way to stub API calls, mock data, and verify that your application is making the correct requests.

Basic Usage

The fundamental syntax of cy.intercept() involves specifying the route you want to intercept and the desired behavior when that route is matched. The route can be defined using a URL string, a regular expression, or an object containing properties like url and method.

Here's a simple example of intercepting a GET request to /api/users and providing a mocked response:

it('should display mocked users', () => {
  cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
  cy.visit('/users'); // Assuming your app fetches users on this page
  cy.wait('@getUsers'); // Wait for the intercepted request
  cy.get('.user-list li').should('have.length', 3); // Assuming users.json has 3 users
});

In this example:

  1. cy.intercept('GET', '/api/users', { fixture: 'users.json' }) intercepts GET requests to /api/users and responds with the data from the users.json fixture file. The .as('getUsers') part assigns an alias to the intercept, allowing you to refer to it later.
  2. cy.visit('/users') navigates to the page where the user data is fetched.
  3. cy.wait('@getUsers') pauses the test execution until the intercepted request is made. This ensures that the mocked data is available before the assertions are performed.
  4. cy.get('.user-list li').should('have.length', 3) asserts that the user list contains the expected number of users (based on the mocked data).

Intercepting Different Request Methods

You can intercept various HTTP methods like POST, PUT, DELETE, etc. For example, to intercept a POST request:

cy.intercept('POST', '/api/login', { statusCode: 200, body: { success: true, token: 'mocked_token' } }).as('loginRequest');
cy.get('#login-form').submit(); // Assuming your login form submits to /api/login
cy.wait('@loginRequest').then((interception) => {
  expect(interception.request.body.username).to.equal('testuser');
  expect(interception.response.body.token).to.equal('mocked_token');
});

Here, we intercept the POST request to /api/login, provide a successful response with a mocked token, and then verify that the request body contains the expected username. The .then((interception) => ...) block allows you to access the intercepted request and response objects for further inspection.

Dynamic Responses and Request Modification

cy.intercept allows for more complex scenarios, such as modifying the request before it's sent or providing dynamic responses based on the request data.

cy.intercept('POST', '/api/items', (req) => {
  if (req.body.name === 'Forbidden Item') {
    req.reply({ statusCode: 403, body: { error: 'Item not allowed' } });
  } else {
    req.continue(); // Let the request proceed to the real server
  }
}).as('createItem');
 
cy.get('#item-form').submit();
cy.wait('@createItem').then((interception) => {
  if (interception.request.body.name === 'Forbidden Item') {
    expect(interception.response.statusCode).to.equal(403);
  } else {
    // Assertions for successful item creation
  }
});

In this example, we intercept POST requests to /api/items. If the request body contains a name of "Forbidden Item", we respond with a 403 error. Otherwise, we use req.continue() to allow the request to proceed to the actual server (if one is configured). This demonstrates how you can conditionally stub responses based on the request data.

Best Practices

  • Use aliases: Assigning aliases to your intercepts using .as() makes your tests more readable and maintainable. It also allows you to wait for specific intercepts using cy.wait().
  • Be specific with routes: Use precise URL strings or regular expressions to target only the requests you intend to intercept. Avoid overly broad patterns that could unintentionally intercept other requests.
  • Clean up intercepts: While Cypress automatically cleans up intercepts after each test, it's good practice to explicitly remove intercepts when they are no longer needed, especially in complex test suites. You can use cy.clearIntercepts() to remove all intercepts.
  • Test different scenarios: Use cy.intercept to simulate various server responses, including success, error, and loading states. This helps ensure that your application handles different situations gracefully.
  • Verify request data: Use the interception.request object to verify that your application is sending the correct data to the server. This helps catch errors related to data formatting or missing parameters.
  • Combine with fixtures: Use fixtures to store mocked data and load it into your intercepts. This makes your tests more organized and easier to maintain.

Common Tools and Techniques

  • Fixtures: Cypress fixtures are JSON files that contain sample data. They are commonly used to provide mocked responses for intercepted requests.
  • Regular Expressions: Regular expressions can be used to define more flexible routes for interception. This is useful when you need to match multiple URLs or URLs with dynamic segments.
  • cy.wait(): The cy.wait() command is used to pause test execution until an intercepted request is made. This ensures that the mocked data is available before assertions are performed.
  • req.reply(): The req.reply() function allows you to send a custom response to the browser, overriding the actual server response.
  • req.continue(): The req.continue() function allows the request to proceed to the actual server. This is useful when you only want to modify the request or response under certain conditions.
  • req.destroy(): The req.destroy() function aborts the request.

By mastering cy.intercept, you can create robust and reliable Cypress tests that are independent of your backend and can handle a wide range of scenarios. This leads to more confident deployments and a better user experience.

Further reading