Home > database >  Cypress - wait for next button to reappear before going on
Cypress - wait for next button to reappear before going on

Time:11-05

I have a cart preview button on the top right of the screen. If I click this button, a div appears. This div lists items in the cart, and below each item there is a "remove" button.

I need to click on every "remove" button of this div, and remove all the items one by one.

The problem is that after I click "remove" a spinner appears for some seconds. When the spinner disappears, appear the rest of the items and the rest of the "remove" buttons.

  cy.get('.cart-toggle-btn').click()
  cy.contains('.remove.btn', 'Remove').each(aaa => {
    aaa.click()
  })

If I use the code above, it only removes the first item, and then the test passes. But there are still other items in the cart.

How can I "tell" cypress to wait for the redux dispatch action to complete (spinner to disappear) and then retry to find the next remove buttons?

Thanks

CodePudding user response:

Factoring in the spinner is a good way to see when the "internal" process is complete and you can proceed with the next remove action.

But you should wait for the spinner to appear, then disappear. In the test, Cypress will check the spinner very quickly, even before it has appeared.

cy.get('.cart-toggle-btn').click()
cy.contains('.remove.btn', 'Remove').each($item => {
  cy.wrap($item).click()
  cy.get('spinner').should('be.visible')       // check visible rather than exists
  cy.get('spinner').should('not.be.visible')
})

With list counter

If you have trouble with the spinner (and don't care about it), check the length of list

If the list re-renders between remove actions, and you get detached from DOM errors, re-query the elements inside the loop

cy.contains('.remove.btn', 'Remove').each($item => {

  // get fresh count each time
  cy.contains('.remove.btn', 'Remove').then($currentList => {  

    const count = $currentList.length   

    cy.contains('.remove.btn', 'Remove').first().click()    // remove one 

    // wait for smaller list (when it's not yet empty)
    if (count > 1) {
      cy.contains('.remove.btn', 'Remove').should('have.length', count -1)
    } else
      cy.contains('.remove.btn', 'Remove').should('not.exist')
    }
  })
})


With conventional Javascript for-loop

This is shorter, using a conventional loop and executing the last remove action outside the loop.

cy.get('.remove.btn').its('length').then(count => {

  for (let index = 1; index < count; index  ) {
    cy.get('.remove.btn').first().click()
    cy.get('.remove.btn').should('have.length', count -index)
  }
  cy.get('.remove.btn').first().click()
  cy.get('.remove.btn').should('not.exist')
})

CodePudding user response:

You can do an assertion on the spinner not existing, and that should tell your test to wait after each .click().

  cy.get('.cart-toggle-btn').click()
  cy.contains('.remove.btn', 'Remove').each(aaa => {
    aaa.click().get('spinner').should('not.exist')
  })
  • Related