'Cypress wait for API after button click

I've made a React app, which all works perfectly and I'm now writing some end to end tests using Cypress.

The React app all works on the same url, it's not got any routes, and api calls from inside the app are handled through button clicks.

The basis of the app is the end user selects some options, then presses filter to view some graphs that are dependant on the selected options.

cy.get('button').contains('Filter').click()

When the button is pressed in cypress, it runs the 3 api calls which return as expected, but looking over the cypress docs there is no easy way unless I use inline cy.wait(15000) which isn't ideal, as sometimes they return a lot faster, and sometimes they return slower, depending on the selected options.

Edit 1 I've tried using server and route:

cy.server({ method: 'GET' });
cy.route('/endpoint1*').as('one')
cy.route('/endpoint2*').as('two')
cy.route('/endpoint3*').as('three')
cy.get('button').contains('Filter').click()
cy.wait(['@one', '@two', '@three'], { responseTimeout: 15000 }) 

Which gives me the error:

CypressError: Timed out retrying: cy.wait() timed out waiting 5000ms for the 1st request to the route: 'one'. No request ever occurred.

After further investigation

Changing from responseTimeout to just timeout fixed the error.

cy.server({ method: 'GET' });
cy.route('/endpoint1*').as('one')
cy.route('/endpoint2*').as('two')
cy.route('/endpoint3*').as('three')
cy.get('button').contains('Filter').click()
cy.wait(['@one', '@two', '@three'], { timeout: 15000 }).then(xhr => {
  // Do what you want with the xhr object
}) 


Solution 1:[1]

Sounds like you'll want to wait for the routes. Something like this:

cy.server();
cy.route('GET', '/api/route1').as('route1');
cy.route('GET', '/api/route2').as('route2');
cy.route('GET', '/api/route3').as('route3');

cy.get('button').contains('Filter').click();

// setting timeout because you mentioned it can take up to 15 seconds.
cy.wait(['@route1', '@route2', 'route3'], { responseTimeout: 15000 });

// This won't execute until all three API calls have returned
cy.get('#something').click();

Solution 2:[2]

Rather than using a .wait you can use a timeout parameter. That way if it finished faster, you don't have to wait.

cy.get('button').contains('Filter', {timeout: 15000}).click()

This is mentioned as one of the options parameters in the official docs here.

Solution 3:[3]

Try this:

    cy.contains('button', 'Save').click();
    cy.get('[data-ng-show="user.manage"]', { timeout: 10000 }).should('be.visible').then(() => {
      `cy.get('[data-ng-show="user.manage"]').click();
   })

Solution 4:[4]

cy.server() and cy.route() are deprecated in Cypress 6.0.0 In a future release, support for cy.server() and cy.route() will be removed. Consider using cy.intercept() instead.

this worked for me...

ex:- see the screen shot

    cy.intercept('GET', 'http://localhost:4001/meta').as('route');
    cy.get(':nth-child(2) > .nav-link').click();
    cy.contains('Filter');
    cy.wait(['@route'], { responseTimeout: 15000 });

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Brendan
Solution 2 Adriano
Solution 3 MarcinW
Solution 4 sachithya rivisara