Working with iFrames in Cypress
Working with iFrames in Cypress
Learn how to work with iFrames in Cypress
iFrames are a feature of the web that allows websites to embed other websites, or web pages, into their existing page.
For instance, here on the kitchen, we’re using an iFrame to embed the table page on the existing iFrame page. If you’re embedding something important to the user’s experience, you want to make sure that you can verify that the embed is working as expected.
If we look inside of the code, typically we would want to look for the ID of the iFrame, which here, we’re using the “the-kitchen-table”. With that ID, we can drill down inside of this page and make sure that our table is showing up as expected.
To start off, I have this test already set up where I’m going to visit that iFrame page every time a test runs. We’re going to use cy.get, where we’re going to pass in the ID of that iFrame (“#the-kitchen-table”), so that we can get its contents. If we drill into that iFrame and find the table, we can see that it has an ID of “fruits-vegetables”.
Now, if this was a typical HTML element, we might run something like .find() , where we would pass in the ID of that table. And then we can write a should assertion for that table’s content. But we can see that when that test runs, when we’re trying to look for that .find(‘#fruits-vegetables’), we’re not actually able to find that table inside of the iFrame.
The issue is with the way that Cypress works, as soon as it sees this document element, embedded inside of the page, it’s going to stop.
How to Access iFrame Object Properties with Cypress
Because Cypress is built on top of JavaScript, we actually have access to the object’s properties, which means we can drill in a little bit manually and find that table.
Before we run this .find() command, we’re going to actually run the .its() command. When we run this command, it’s going to let us access some of the properties of this object that we’re getting.
Now that we have “the-kitchen-table” iFrame, we’re I use .its() is, and we’re going to first access the zero (0) index of the array of values from our .get() command. Then we’re going to say, we want to access its(‘0.contentDocument’), where then finally we want to access its(‘body’) .
We can see similarly how this would work right inside of our browser, where if we want to querySelectorAll(‘iframe’) on the iFrame, we’re going to see that we have 2 nodes where we’re running the same site and the cross domain. But if we first access the zero index of that, and then as well as the contentDocument and body, we can see that we’re actually grabbing that body of the iFrame.
Now that we actually have the body of the iFrame, we want to do one more thing. We want to run .then() where we’re going to run cy.wrap — .then(cy.wrap).
What it’s going to do is it’s going to take that body, and it’s going to wrap it inside of a Cypress selector. That way we can use the same methods and API that we would typically use.
We can now see that after it went through all those steps, it was able to grab the body of the iFrame. It was then able to wrap it with Cypress, where we could then use that .find() command successfully where we were able to find “the-kitchen-table”.
Finally, now that we have our element, we can write our assertion where we can write .should(‘be.visible’). We can see just like before it was able to find that table, and as expected, it’s visible.
Cypress Limitations with Cross Domain iFrames
Now, the tricky thing with iFrames and Cypress is this only works when you’re using a website from the same origin. If we have a cross domain iFrame, such as that of a YouTube in embed, we’re not going to be able to actually access it due to the browser rules for security policies.
We can even see that’s the case, if we run back to the querySelectorAll, try to grab that YouTube video and then run contentDocument, we can see that it returns null.
So, if we wanted to try to write a test similar to our first one, where we wanted to look and see that the player is inside of our YouTube iFrame, as expected, we weren’t able to actually access the body of that cross domain iFrame.
Summing It Up – Testing iFrames with Cypress
In review, we wanted to test that our iFrames were loading on our page successfully. We were able to find out that we were able to do that a little bit differently than we would typically do for finding an ID.
We first grabbed that iFrame by ID. We then accessed its(‘0.contentDocument.body’). We then wrapped that element with Cypress using cy.wrap. We can then find the ID of the table and check that it’s visible.
But if we were trying to test the same exact thing with a cross domain iFrame, we found out that we weren’t going to have luck due to the browser security policy.
Resources
- Git Repo – iframe.spec.js
- Applitools Kitchen – iFrame Testing