Mastering Advanced Cypress.io Test Automation [Part 2/4]: Network Stubbing
Tags: cypress, testing, javascript, e2e
Published: 2023-05-12 01:25:10

With the examples covered in this part, you’ll gain a strong grasp of network stubbing in your Cypress.io test suite and be one step closer to mastering advanced Cypress.io test automation. So, let’s get started!

## Network Stubbing
Another challenge in web application testing is dealing with network requests. In some cases, you may want to simulate network responses in your tests. For example, you might want to test how your application handles errors or slow network connections.

The `cy.intercept()` command is used to intercept specific network requests and provide custom responses. You can pass in the HTTP method, URL, and response object as arguments to the `cy.intercept()` command. The response object can include a fixture, which is a static JSON file that serves as a mock response.

Let’s take a look at some code examples to see how network stubbing works in Cypress.

### Example 1: Simulating a Slow Network Connection
In this example, we’re intercepting a GET request to the URL `https://api.example.com/users` and responding with a fixture called “_users.json_”. We’re also using the `cy.wait()` command to simulate a slow network connection.

```
describe('Network Stubbing', () => {
  beforeEach(() => {
    cy.intercept('GET', 'https://api.example.com/users', {
      fixture: 'users.json'
    }).as('getUsers')
  })
  
  it('Visits a website that uses an external API', () => {
    cy.visit('https://www.example.com')
    cy.wait('@getUsers').then(({ response }) => {
      expect(response.statusCode).to.equal(200)
      expect(response.body).to.have.length(2)
      expect(response.body[0]).to.have.property('name', 'FirstName LastName')
    })
  })
})
```

Let’s break down the code step by step:

1. The `describe` function is used to group related tests together. In this case, we’re grouping tests related to network stubbing.
2. The beforeEach function is used to set up a mock server and define a route for the server to respond to using `cy.intercept()`. In this case, we’re intercepting a GET request to the URL `https://api.example.com/users` and responding with a fixture called “_users.json_”.
3. The test, `it('Visits a website that uses an external API', ()=>{...})`, visits a website and waits for the response from the mocked API route we defined earlier using `cy.intercept()`. Once the response is received, we use the `.then()` function to perform assertions on the response. In this case, we’re asserting that the response has a status code of 200, has a length of 2, and that the first user object has a name of _‘FirstName LastName’_.

### Example 2: Handling Dynamic Responses
In this example, we’re intercepting a dynamic API route and responding with user data. We’re using the `.its()` function to drill down into the response JSON and check that the data returned for the user with ID 1 matches our expected data.

```
it('Handles dynamic response', () => {
  // Intercept the dynamic API route and respond with user data
  cy.intercept('GET', '/api/users/*', req => {
    req.reply({
      statusCode: 200,
      body: {
        id: req.path.split('/')[3],
        name: 'FirstName LastName',
        email: 'fullname@example.com',
        age: 30
      }
    })
  }).as('dynamicApiRoute')
  // Visit a website and wait for response from mocked API route
  cy.visit('/')
  cy.wait('@dynamicApiRoute')
  // Assert that the response contains the correct user data
  cy.get('@dynamicApiRoute')
    .its('response.body')
    .should('deep.equal', {
      id: '1',
      name: 'FirstName LastName',
      email: 'fullname@example.com',
      age: 30
    })
})
```

Here is a step-by-step breakdown of the code example:

1. We start with the test case description: “Handles dynamic response”.
2. We then use the `cy.intercept()` method to intercept a dynamic API route. The route is defined with a wildcard `*` in the URL path, which means that any URL that matches the pattern /`api/users/*` will be intercepted.
3. Inside the intercept method, we use the `req.reply()` method to respond with user data. The req object contains information about the intercepted request, including the URL path. We extract the user ID from the URL path using the `.split()` method and add it to the response body.
4. We then visit a website using the `cy.visit()` method and wait for the response from the mocked API route using the `cy.wait()` method. Note that we haven't defined an alias for this route yet.
5. We define an alias for the intercepted route using the `.as()` method. We use the name `dynamicApiRoute` as the alias.
6. We then assert that the response contains the correct user data. We use the `cy.get('@dynamicApiRoute')` method to get the response for the intercepted route using the alias. We then use the `.its()` method to access the response.body property of the response. Finally, we use the `.should()` method with the `deep.equal` assertion to compare the response body with the expected user data.

### Example 3: Handling Errors
In this example, we’re intercepting an API route that returns a 500 server error using `cy.intercept()`. Once again, we’re visiting the website and waiting for the response from the mocked API route. We’re then checking that the response contains the expected error message.

```
it('Handles errors', () => {
  // Intercept an API route that returns a 500 server error
  cy.intercept('GET', '/api/error', {
    statusCode: 500,
    body: 'Internal Server Error'
  }).as('errorRoute')
  
  // Visit the website and wait for response from mocked API route
  cy.visit('/')
  cy.wait('@errorRoute').then(({ response }) => {
    expect(response.statusCode).to.equal(500)
    expect(response.body).to.equal('Internal Server Error')
  })
})
```

The test first intercepts the API route that returns a 500 server error using `cy.intercept()`. The method takes three arguments: the HTTP method, the URL to intercept, and an object containing the response to return. In this case, we're returning a response with a status code of 500 and a body of "Internal Server Error". We also give this intercept a unique name using `.as('errorRoute')` so that we can reference it later.

Next, we visit the website using `cy.visit()` and wait for the response from the mocked API route using `cy.wait('@errorRoute')`. Once the response is returned, we can access it in the callback function using destructuring to get the `response` object.

Finally, we use `expect()` to check that the response contains the expected error message. We check the `statusCode` property of the response to ensure that it is 500, and we check the `body` property of the response to ensure that it matches the expected "Internal Server Error" message.

By intercepting and mocking API routes in this way, we can simulate different responses from the server and ensure that our frontend code handles them correctly. This makes it easier to test our application and catch errors before they make it to production.

**Summary:** Overall, these examples demonstrates how to use network stubbing in Cypress.io to mock API responses and control the data returned by the API. By using network stubbing, we can ensure that our tests are predictable and repeatable, even when testing applications that rely on external APIs.

---
_If you liked this, click ❤ so other people will also notice here._