4

How do I write a cypress visible assertion for an element whose parent has css property hidden? I have the following HTMl code

<td class="item-total item-total-mobile-hidden">
<p class="mobile-show block-price-text">Total Price:</p>
<span class="price-total">
$699.99
</span>
</td>

When I write the following cypress code to assert that the price element is visible

Cy.get('.price-total').should('be.visible')

I get this error message Timed out retrying: expected '<span.price-total>' to be 'visible'

This element <span.price-total> is not visible because its parent <div.item-total-price-mobile-show> has CSS property: display: none

I have to tried to debug this on the console (putting the span in a variable $0)

$0
<span class=​"price-total">​ $699.99 ​> ​ Cypress.dom.isVisible($0) true

Here is shows the span element is isVisible true, but I am unable to assert it. I tried the following by invoking the text on the child element, but it didn't work either

cy.get('.price-total').invoke('text')
      .then((text)=>{
        const divTxt = text;
expect(divTxt).to.be.visible; })

This did not work, I get the following error because cypress couln't find the hidden element Timed out retrying: Expected to find element: .price-total, but never found it.

What's the best way to assert that the element <span class=​"price-total">​ is visible?

Jin
  • 69
  • 2
  • 3
  • 11

3 Answers3

4

I'm not sure I'm getting the complete picture, but good skills checking Cypress.dom.isVisible($0).

You can use the exact same expression in your test by using .should() with a callback

cy.get('.price-total')
  .should($priceEl => {     // retries if necessary when expect fails

    expect(Cypress.dom.isVisible($priceEl).to.eq(true)

  })

I'm not sure this is definitive, have seen an Angular app (select control) where the parent was display: none but the child was visible to the user (ref Access element whose parent is hidden)

In this answer, a custom function is used to redefine the criteria for visibility. The trick is to figure out what to check for your app...

// Change this function if other criteria are required.
const isVisible = (elem) => !!( 
  elem.offsetWidth ||                          
  elem.offsetHeight || 
  elem.getClientRects().length 
)

You may just have a delay (e.g animation) before the parent element removes display: none.

Check the parent in the console, see if it eventually has a different display value.

In that case, first check the parent (not the child as Manuel says).

cy.get('td.item-total')
  .should('not.have.css', 'display', 'none')  
  .find('.price-total')
  .should($priceEl => {     
    expect(Cypress.dom.isVisible($priceEl).to.eq(true)
  })
1

You can retry while .price-total CSS has the "display: none" property like so:

cy.get('.price-total').should('not.have.css', 'display', 'none')
Manuel Abascal
  • 5,616
  • 5
  • 35
  • 68
  • 2
    This would be a "double negative" validation of an element that is visible, I would prefer to have a straight forward validation of "is visible". But if nothing else works I would have to use it, I will probably add additional check that the element doesn't have "hidden" property – Jin Mar 15 '21 at 23:16
  • 1
    Found this page to be very useful also https://github.com/cypress-io/cypress/issues/877 – Jin Mar 15 '21 at 23:23
0

If the parent of the element you are looking for has display:none then your element is not displayed(not visibled), to see that this is true just put:

cy.get('.price-total').should('be.not.visible')

Note: I am using cypress version: 8.3.1

Jaime Roman
  • 749
  • 1
  • 11
  • 26