Reputation: 73
I have a problem when using cy.getIframeBody().find('#some-button')
that the #some-button element is not yet available, because the iframe is still loading, but the body element is not empty so the .find() is triggered.
This is the custom command to get the iframe body
Cypress.Commands.add('getIframeBody', ()=> {
return cy.get('iframe.cy-external-link-container')
.its('0.contentDocument.body')
.should('not.empty')
.then(cy.wrap)
});
How I can do it without using cy.wait()
?
Upvotes: 6
Views: 2307
Reputation: 31904
You can add random timeouts and .should()
assertions, but if they work at all the test is likely to be flaky.
The key is to repeat the query of the body element (this line)
.its('0.contentDocument.body')
until the button shows up.
So not
.its('0.contentDocument.body')
.should('not.empty')
but something like
.its('0.contentDocument.body')
.should('have.child', '#some-button') // force a retry on body query
.should()
with callback will do this
Cypress.Commands.add('getIframeBodyWithSelector', (waitForSelector) => {
return cy.get('iframe.cy-external-link-container')
.its('0.contentDocument.body')
.should(body => {
expect(Cypress.$(body).has(waitForSelector).length).gt(0)
})
.then(cy.wrap)
})
it('finds some button', () => {
cy.getIframeBodyWithSelector('#some-button')
.find('#some-button') // passes
})
Upvotes: 10
Reputation: 18650
You can add an timeout and also add should('be.visible')
. should assertion will make sure that till the timeout value is reached it rerties and make sure that the iframe is loaded successfully.
Cypress.Commands.add('getIframeBody', () => {
return cy
.get('iframe.cy-external-link-container', {timeout: 7000})
.should('be.visible')
.its('0.contentDocument.body')
.should('not.empty')
.then(cy.wrap)
})
Upvotes: 1