Cypress.io - Assert no XHR requests to URL?

Viewed 4485

When testing with cypress.io, is there a good way to assert that no XHR requests were made to a given URL?

I want to assert that a new foo is added when the "Save" button is clicked, but not when the "Cancel" button is clicked.

Something like this:

cy.route('POST', '/foos').as('postFoo');
cy.get('.cancel-button').click();
cy.route('@postFoo').should('not.have.been.called'); // (magic imaginary syntax!)

I've tried setting up the cy.route with an onRequest callback that does an assert.fail, but that's not failing the test when the the URL is called.

For now, I'm catching my (intentional) "no request occurred" errors like this:

cy.on('fail', (err, runnable) => {
  expect(err.message).to.include('No request ever occurred.');
  return false;
});  

cy.wait('@postFoo', { timeout: 0 }).then(xhr => {
  throw new Error('Unexpected API call.');
});

...which seems to be working, but it certainly doesn't feel very "cypress-y".

3 Answers

You can re-alias your route and change its onRequest behavior to throw; however it's generally worse to assert that things didn't happen because they are non-deterministic. How long should you wait around for the error before moving on? :

cy.route({
  method: 'POST',
  url: '/foos',
  onRequest: () => {
    throw new Error('Whoops')
  }
})
cy.get('.cancel-button').click();
cy.wait(1000)  // give it one second to throw, then move on

Having assertions like this will only add unnecessary time to your tests. This type of test is know as Conditional Testing as mentioned in the Cypress Docs

I think you could compare the data in cy.state('routes') and check the states.

let routes = cy.state('routes');
// check each URL and if it has "/foos" in it, add it to an array to test
// this step is just an example, there are plenty of different ways to approach this
let foosRoutes = [];
for (let route in routes) {
  for (let req in routes[route].requests) {
    let reqUrl = routes[route].requests[req].request.url;
    // test each URL for "/foos" and if it has it, add the URL to the array
    if((/\/foos/).test(reqUrl)) {
      fooRoutes.push(reqUrl);
    }
  }
};
expect(foosRoutes).to.have.property("length", 0);

Or if you dig through the cy.state('routes') a different way, maybe you can filter by the alias of postFoo and then make sure its requests is empty or the count you expect.

The assertion:

.should('not.have.been.called')

cannot be used to check if a network request has been made. It is used for cy.spy()

Your hack works, but you can also try:

cy.intercept('POST', '/foos').as('postFoo');
cy.get('.cancel-button').click();
cy.wait('@postFoo').should('not.exist'); // (magic imaginary syntax!)
Related