Below is the snippet that waits for the content inside the iframe to be loaded and HTMLElements be available & no timeouts required.
const iframeElement = (selector) => {
const iframe = cy.get(selector);
return iframe
.should(($iframe) => // Make sure its not blank
expect($iframe.attr('src')).not.to.include('about:blank')
)
.should(($iframe) =>
expect($iframe.attr('src')).not.to.be.empty) // Make sure its not empty
.then(($inner) => {
const iWindow = $inner[0].contentWindow;
return new Promise((resolve) => {
resolve(iWindow);
});
})
.then((iWindow) => {
return new Promise((resolve) => {
iWindow.onload = () => { // Listen to onLoad event
resolve(iWindow.document);
};
});
})
.then((iDoc) => {
return cy.wrap(iDoc.body); // Wrap the element to access Cypress API
});
};
Now access the element inside the iframeDocument
iframeElement('#my-iframe') // Grab the iframe
.find('h2')
.should('have.text', 'My header text'); //Assert iframe header
Note: Don't attempt to access CORS websites. It might fail due to
security reasons