skip to Main Content

This code waits for a response and does things once it arrives.
How can I do stuff when wait times out?

    cy.wait('@login').then((interception) => {
        const token = interception.response.body.token
        Cypress.env('ACCESS_CODE', token)
    }); 

2

Answers


  1. Achieving this isn’t possible in Cypress without a little maneuvering to get around the fact that cy.wait() doesn’t really support conditional results.

    But, we can use an undocumented feature of cy.get() to get all aliased calls and check the length of that yielded array to determine our actions:

    cy.intercept('/foo').as('foo');
    // Cypress code that triggers the `/foo` call
    cy.get('@foo.all').then((foo) => {
      if (foo.length > 0) {
        // code to do if the call is made
      } else {
        // code to do if the call is not made
      }
    });
    

    However, cy.get('@alias.all') does not have any waiting or retry mechanism, so if the call is triggered but not completed before calling cy.get(), the call may not appear in the yielded array.

    If that is the case, we can swallow the Cypress error.

    cy.on('fail', (err, runnable) => {
      if (err.message.includes('route: `foo`')) { // check the error message
        // code to execute if call is not made
        return false // returning false makes sure the test does not fail at this step
      }
      throw err // throw the error if we don't return false earlier, to ensure other test failures are still raised  
    })
    

    Two important things:

    • Using cy.on() instead of Cypress.on() will limit the changing of the event to only a specific test. If you’d like to implement this across your test suite, you’d want to do it in your support file and use Cypress.on().
    • return false/throw err -> include these so that your test won’t fail for the specified failure but will fail for unexpected failures.

    Now, given all of the above, I’d highly recommend not doing either of these. They are possible, but the ideal solution is to write your test or app in a way that is determinant and reproducible. (In an ideal test,) There shouldn’t be uncertainty about if a call is made or not. If this is reaching out to a third party resource, I’d maybe recommend stubbing or mocking out the entire flow to eliminate this ambiguity, and have other focused tests on the integration between the third party and your app.

    Login or Signup to reply.
  2. There is no .catch() to cy.wait('@alias'), but you can use this example Request-Polling with some modifications.

    In the following example cy.catchAlias() polls the intercept instead of cy.wait('@alias').

    I have two intercepts in the test, but only the first one is triggered.

    The "failed" intercept returns null instead of failing the test, and you can test the returned value to perform your on-fail actions.

    Cypress.Commands.add('catchAlias', (alias, {timeout = Cypress.config('defaultCommandTimeout'), start = Date.now()})  => {
      if (start + timeout < Date.now()) return null
      cy.get(alias, {log:false}).then(interception => {
        if (interception?.response) return interception
        cy.catchLogin(alias, {timeout, start})
      })
    })
    
    cy.intercept('/todos/1').as('api1')
    cy.intercept('/todos/2').as('api2')
    
    cy.window().then(win => {
      win.fetch('https://jsonplaceholder.typicode.com/todos/1')
    })
    
    cy.catchAlias('@api1', {timeout:2000})
      .should(interception => {
        expect(interception.response.body.title).to.eq('delectus aut autem')
      })
    
    cy.catchAlias('@api2', {timeout:2000})
      .should('eq', null)
    

    cypress-wait-if-happens

    Gleb Bahmutov has a plugin cypress-wait-if-happens to do the same thing, with more options.

    if the request does not happen within the timeout, yields undefined

    import 'cypress-wait-if-happens'
    cy.waitIfHappens({
      alias: '@users',
      timeout: 100,
      lastCall: true,
      yieldResponseBody: true,
    })
      // we should get the list with 4 users
      // because that is the last call that happens
      .should('have.length', 4)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search