Igor Vlasuyk
Igor Vlasuyk

Reputation: 574

How to wait until iframe will be loaded with Cypress

I have dynamically loading iframe in a application.

I'm catching a frame through this code:

Cypress.Commands.add('getIframe', (iframeLocator: string): void => {
cy.wait(10000)
cy.get(iframeLocator)
    .its('0.contentDocument').should('not.be.empty')
    .its('body').should('be.visible')
    .then(cy.wrap)
})

The problem is that - without explicit timeout cy.wait(10000) conditions not.be.empty and be.visible are passing fine, while there is no content of iframe on the page yet.

How to catch iframe without explicit wait ?

Upvotes: 0

Views: 5897

Answers (3)

Fody
Fody

Reputation: 31944

There are a couple of things that can stop <iframe> code working, including cypress-iframe.

  • lazy-loading

    <iframe src="https://example.com"
            loading="lazy"                  
            width="600"
            height="400"></iframe>
    

    Standardized lazy-loading of iframes defers offscreen iframes from being loaded until the user scrolls near them. This saves data, speeds up the loading of other parts of the page, and reduces memory usage.


  • default loading content message e.g "Page is loading", falsely passes the .should('not.be.empty') check

  • <body> element is changed when proper page is available, negating .its('body').should('be.visible') check

These are the additional steps I use

// when iframe has attribute loading="lazy" 
cy.get(iframeLocator).scrollIntoView()   // start loading

cy.get(iframeLocator)
  .its('0.contentDocument').should('not.be.empty')
  .its('body')
  .as('body')           // alias this command chain

cy.get('@body')         // repeats above chain when <body> detached from DOM (replaced)
  .should('be.visible')
  .should('not.be.empty')
  .then(cy.wrap)
  .find('div#some-content', {timeout:10000})

Upvotes: 2

TesterDick
TesterDick

Reputation: 10555

An iframe may have "iframe is loading" default, so not.be.empty or be.visible are false checks.

Try content check and make sure <body> query is retried

Cypress.Commands.add('getIframe', (iframeLocator: string): void => {
cy.get(iframeLocator)
    .its('0.contentDocument').should('not.be.empty')
    .its('body h1').should('contain', 'IFrame title')    // retry body
    .then(cy.wrap)
})

Upvotes: 1

Alapan Das
Alapan Das

Reputation: 18634

You can use the cypress-iframe plugin for this. After installing you can use the frameLoaded method.

// This will verify that the iframe is loaded to any page other than 'about:blank'
cy.frameLoaded()
 
// This will verify that the iframe is loaded to any url containing the given path part
cy.frameLoaded({ url: 'https://google.com' })
cy.frameLoaded({ url: '/join' })
cy.frameLoaded({ url: '?some=query' })
cy.frameLoaded({ url: '#/hash/path' })
 
// You can also give it a selector to check that a specific iframe has loaded
cy.frameLoaded('#my-frame')
cy.frameLoaded('#my-frame', { url: '/join' })

Upvotes: 0

Related Questions