Get All Intercepted Network Calls In Cypress

Use the `alias.all` syntax to get all intercepted network calls at once.

This blog post describes a topic really hidden in Cypress documentation: using alias.all to get all intercepted network calls.

Intro

Using Cypress cy.intercept command you can spy on or stub network calls the application makes. Once the intercept is in place, you can click on a button, the application makes a network call, and you can check the intercepted call using the cy.wait command.

1
2
3
4
5
// 💡 always set up network intercepts BEFORE the action
cy.intercept('GET', '/comments/*').as('networkCall')
cy.contains('button', '3 network calls').click()
// confirm the 3 calls are made
cy.wait('@networkCall').wait('@networkCall').wait('@networkCall')

Even if the network calls are made after some delay, Cypress waits for the calls to happen.

🎁 Examples used in this blog post are available on my site glebbahmutov.com/cypress-examples. This particular post is shown in the recipe Get All Intercepted Network Calls. For more in-depth network examples and exercises, see my online course Cypress Network Testing Exercises.

What if you do not know the number of calls to expect? What if you need more flexibility when checking the network calls?

Get all network calls

The syntax cy.get('alias.all') is the solution. It yields an array of all current intercepted network calls for the given alias. It might be an empty array. Let's confirm the application makes 3 calls to GET /comments/* using cy.get('alias.all') syntax.

1
2
3
4
5
// 💡 always set up network intercepts BEFORE the action
cy.intercept('GET', '/comments/*').as('networkCall')
cy.contains('button', '3 network calls').click()
// confirm the 3 calls are made using cy.get
cy.get('@networkCall.all').should('have.length', 3)

The video below shows how Cypress keeps retrying until the assertion have.length 3 passes.

We can click on the cy.get command to see the array of intercepted network calls.

Intercepted network calls

Each intercept has the request and the response objects, plus a few other internal properties.

A single intercept object

We can treat these intercepts as plain objects and make assertions against them.

Wait for a network intercept

We can combine cy.get('alias.all') and cy.wait('alias') calls - they work independently. Each intercept has responseWaited property that changes on each cy.wait('alias') command. Using query commands from my cypress-map plugin we can confirm it

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// confirm the 3 calls are made using cy.get
cy.get('@networkCall.all').should('have.length', 3)

cy.log('**cy.wait effect**')
cy.get('@networkCall.all')
.map('responseWaited')
.should('deep.equal', [false, false, false])
cy.wait('@networkCall')
cy.get('@networkCall.all')
.map('responseWaited')
.should('deep.equal', [true, false, false])
cy.wait('@networkCall')
cy.get('@networkCall.all')
.map('responseWaited')
.should('deep.equal', [true, true, false])

Waiting for each network call

Flexible assertions

Using cy.get(alias.all) lets you create very flexible assertions. For example, the application might make multiple calls to the backend. We are only interested in specific responses. In the test below, we confirm the application eventually returns comment with id=2. Here is the application code I will be testing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// we fetch all data from this REST json backend
const root = 'https://jsonplaceholder.cypress.io'

function getComment(id = 1) {
$.ajax({
url: `${root}/comments/${id}`,
})
}

$('.network-count-btn').on('click', function (e) {
e.preventDefault()
setTimeout(getComment, 1000 * Math.random())
setTimeout(getComment.bind(null, 2), 2000 * Math.random())
setTimeout(getComment, 3000 * Math.random())
})

Notice that only one of the calls is fetching the /comments/2 resource. To confirm this call happens, we can use cy.get('alias.all') and inspect the response objects.

1
2
3
4
5
6
7
8
9
cy.intercept('GET', '/comments/*').as('networkCall')
cy.contains('button', '3 network calls').click()
// confirm that at least one call returns an object with ID = 2
cy.get('@networkCall.all').should((interceptions) => {
const hasId2 = interceptions.some(
(x) => x.response.body.id === 2,
)
expect(hasId2, 'response with id 2').to.be.true
})

The combination of query cy.get('alias.all') plus assertion should(callback) keeps retrying until the application makes the call with response id: 2

Nice. We can simplify the should(callback) using query commands from my cypress-map plugin

  • map each intercepted call to its response.body.id deep property
    • this yields an array of ids
  • assert the array includes the value 2

which looks like this

1
2
3
4
5
6
7
cy.intercept('GET', '/comments/*').as('networkCall')
cy.contains('button', '3 network calls').click()
// confirm that at least one call returns an object with ID = 2
cy.get('@networkCall.all')
.map('response.body.id')
.print() // helpful query from cypress-map to print the current subject
.should('include', 2)

Notice how the test finishes even before the third call is made - because the assertion include 2 passes on the second intercepted call. Beautiful.