Cypress wait for API after button click

15,593

Solution 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

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.

Share:
15,593

Related videos on Youtube

Geoff
Author by

Geoff

Updated on September 15, 2022

Comments

  • Geoff
    Geoff over 1 year

    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
    }) 
    
  • Geoff
    Geoff almost 5 years
    I'll try that when I'm next on it. Cheers.
  • Josh Pittman
    Josh Pittman almost 5 years
    Your wait probably goes after the bit of code you posted, in which case you would want to add the timeout to the next assertion. It works the same way. Almost all of the cypress methods have a timeout parameter, not just 'contains'. Paste your next assertion in to question if you are having trouble.
  • Geoff
    Geoff almost 5 years
    Looks like exactly what I want, I tried it before, but didn't have the timeout on it, so explains exactly why it didn't work. I'll see Monday and reply then. Cheers.
  • Geoff
    Geoff almost 5 years
    I've edited the question with what happens trying this method.
  • Geoff
    Geoff almost 5 years
    This works, but it's not very graceful the method in Brendans answer is how it's intended to be done with Cypress.
  • Josh Pittman
    Josh Pittman almost 5 years
    I disagree. Your answer assumes you are working with restful APIs. When this question was first posted, this was not the case. My approach work with web sockets, streams, and graphql. More robust.
  • Josh Pittman
    Josh Pittman almost 5 years
    Define graceful. You added 5 extra lines and achieved the same as what I did in 15 colocated characters. Please leave both answers up because they are both useful approaches for different situations.
  • Geoff
    Geoff almost 5 years
    It adds more code, sure, but the added code makes it a lot clearer what's intended to be done. It also gives the test access to the responses from the api calls.
  • Brendan
    Brendan almost 5 years
    @Geoff I see that timeout worked for you instead. You're likely on an older version of Cypress, that was split out in version 3.1.3. you'll need to change it to responseTimeout once you upgrade. docs.cypress.io/guides/references/changelog.html#3-1-3
  • Josh Pittman
    Josh Pittman almost 5 years
    I agree, but my point is that this is a different requirement, not a better one. Perhaps change the question title to 'Cypress wait for rest api response' to better direct other people searching for the same issue.
  • Geoff
    Geoff almost 5 years
    "cypress": "^3.3.2" strange... although I have got this working with putting responseTimeout: 15000 in cypress.json. timeout does work on it's own in the wait command.
  • Geoff
    Geoff almost 5 years
    Taken on board, question changed.