Element Hides

📺 Watch the explanation for this recipe in the video Element Hides Vs Element Is Removed From The DOMopen in new window.

Element is removed from the DOM

Imagine the element the user clicks, like a button. The button adds a class "away" after some time, and then is removed from DOM completely. It is a good example of automating waiting.

.half {
  opacity: 50%;
}
<button id="away">Click me</button>
<script>
  const btn = document.getElementById('away')
  btn.addEventListener('click', () => {
    setTimeout(() => {
      btn.classList.add('half')
    }, 1000)
    setTimeout(() => {
      btn.parentElement.remove(btn)
    }, 2000)
  })
</script>
cy.contains('button', 'Click')
  .click()
  .should('have.class', 'half')

Now let's confirm the element goes away completely. We cannot attach another assertion to the same cy.get(...) command:

// 🚨 INCORRECT, JUST A DEMO
// "Element is detached from the DOM" error
cy.contains('button', 'Click')
  .should('have.class', 'half')
  .and('not.exist')

The above assertions cannot be both true at the same time; since the element is removed from the DOM, we want to check it separately.

cy.contains('button', 'Click').should('not.exist')

Element becomes invisible

Now let's take a similar example, but this time the button simply hides after a delay using display: none style.

.half {
  opacity: 50%;
}
<button id="away">Click me</button>
<script>
  const btn2 = document.getElementById('away')
  btn2.addEventListener('click', () => {
    setTimeout(() => {
      btn2.classList.add('half')
    }, 1000)
    setTimeout(() => {
      btn2.style.display = 'none'
    }, 2000)
  })
</script>

This time we can chain the same two assertions to the same DOM element.

cy.contains('button', 'Click')
  .click()
  .should('have.class', 'half')
  .and('not.be.visible')

Since the element is still in the DOM, and it still has the class "half", both assertions can pass at the same time for the same found element.