Search code examples
javascriptcypresswaitassertion

Cypress assertion - element is actionable / not covered


I would like to expand on this question as I have a similar question:

I want to cy.get('#lead_name').type('foo') but it is covered by this element with opacity 0.9 while the form is loading:

<div class="blockUI blockOverlay" style="z-index: 1000; border: none; margin: 0px; padding: 0px; width: 665px; height: 100%; top: 0px; left: 0px; background-color: rgb(0, 0, 0); opacity: 0.9; cursor: wait; position: absolute;"></div>

When I start with the assertion

cy.get('#lead_name').should('be.visible)

it passes the assertion (maybe because of the opacity?) but when I then try to type in the field, I get the error message that the element is covered.

When I try to assert that the overlay is not there anymore and add

cy.get('.blockUI blockOverlay').should('not.exist')

Cypress also passes the assertion even though the element does exist and covers the other element and cy.get('#lead_name').type('foo') fails.

Is there any way to address this problem like

//This does not work it's just a sample to explain what I want to do
//test if the element I want to get is not covered
cy.get('#lead_name').should('not.be.covered')
//or test if the element is actionable
cy.get('#lead_name').should('be.actionable')

to make sure it waits until the form has loaded?

{edit} This is the error message I get from Cypress:

Timed out retrying after 4000ms: cy.type() failed because this element:

<input name="CrmLead[first_name]" id="CrmLead_first_name" type="text" maxlength="255">

is being covered by another element:

<div class="blockUI blockOverlay" style="z-index: 1000; border: none; margin: 0px; padding: 0px; width: 665px; height: 100%; top: 0px; left: 0px; background-color: rgb(0, 0, 0); opacity: 0.9; cursor: wait; position: absolute;"></div>

{edit 2} This is the code I use, condensed to the relevant parts:

it('should select new lead', () {
cy.visit(Cypress.env('lead_url'))
cy.get('#new_lead).click() //this opens the new form which takes some time to load
cy.get('#lead_name').type('foo')
cy.get('#lead_last_name').type('bar')
cy.get('.button').click()
}

{edit 3} The more I test possible solutions, the more I become convinced that the problem is not the overlay, but something in the Cypress code itself.

When I open the form manually it never takes more than a second for the loading spinner to disappear, usually just 0.1-0.2 seconds.

Yet when Cypress opens the form the form just doesn't load properly as the loading spinner stays there indefinitely.


Solution

  • The checking of the overlay should be done in two steps.

    cy.get('.blockUI.blockOverlay')
      .should('exist')
      .then($overlay => $overlay.remove()) 
    cy.get('.blockUI.blockOverlay').should('not.exist')
    
    cy.get('#lead_name', {timeout: 10000})
    .should(($el) => {                    // should will cause retry
      return Cypress.dom.isFocusable($el) // instead of visible, more relevent to actionability
    })
    

    It's possible if you just do the second step, Cypress passes that command before the overlay is present.

    It's the same principle as checjing a loading spinner, which has be tackled on SO before.

    BTW you are selecting an element with two classed (according to the error message), so you need two . in the selector.

    Perhaps that's the only change you need!


    I added another check above that might help. Cypress.dom.isFocusable.

    From the docs Is focusable

    Cypress internally uses this method everywhere to figure out whether an element is hidden, mostly for actionability.


    If you get really stuck, take a look at Gleb Bahmutov's walkthrough video here Debug the Element Visibility Problems in Cypress


    One more idea - you can try removing the covering overlay in the test - added a line to the sample above.