Testing iframes with Playwright

Debbie O'Brien - Mar 24 '22 - - Dev Community

Have you ever had to test something in an iframe on your page with end to end testing? Even testing the play button of an embedded video used to be difficult but then along came Playwright, reliable end-to-end testing for modern web apps. Let's take a look at how Playwright can help you test iframes.

Locators

Before we dive into testing iframes let's first understand how Playwright works when it comes to using locators.

A locator is a way to find element(s) on the page at any moment with built in auto-waiting and retry-ability. That means no set timeouts are needed as Playwright will auto wait for the element to appear, including iframes.

Locators are created with the page.locator(selector[, options]) method.

diagram showing locators in use

Strict by default

Locators are strict by default meaning it will throw an error if it finds more than one.

await page.locator('button').click()
Enter fullscreen mode Exit fullscreen mode

So imagine this scenario where we have many buttons on the page. If there is more than one button element on the page then the test will fail as it won't know which button you want it to click on.

page showing multiple card components with the same button

Locators + first

There are many ways to fix this but one example is to choose the first instance of the button.

await page.locator('button').first().click()
Enter fullscreen mode Exit fullscreen mode

Locators + nth-child

Another option is to use the CSS nth-child selector. This will select the element that is the nth-child of it's parent. In this case the first one.

await page.locator('div:nth-child(1) button').click()
Enter fullscreen mode Exit fullscreen mode

Locators + hasText

Another options is using HasText which is case insensitive substring matching and accepts both strings and regular expressions. This means we can search in every div with the class of 'shoes-card' and find the one which has the text 'Guchi' and locate the button inside of it.

await page
  .locator('.shoes-card', { hasText: 'Guchi' })
  .locator('button')
  .click()
Enter fullscreen mode Exit fullscreen mode

Locators + has:

Another option similar to the one above is to use the has: option which makes sure it contains another locator inside of it.

await page
  .locator('.shoes-card', { has: page.locator('text=Guchi') })
  .locator('button')
  .click()
Enter fullscreen mode Exit fullscreen mode

To show you another example of this in action we have a shopping cart page with items in a cart. We want to select the remove from cart button to make sure we can remove a specific item from the cart.

Again we use the has: option to find the row that has the a locator this time using the image alt selector with the value of 'Guchi'. Our locator now concentrates only inside this one row and locates the button with the aria label of remove from cart. Again we need to be careful of strict mode and ensure we really only have one image alt with the value of 'Guchi' otherwise our test will fail.

code example showing a shopping cart rows with an arrow pointing to the button of only one row

Frame Locators

When testing iframes we can use the FrameLocator which allows us to retrieve the iframe and locate elements inside that iframe. For example we could test a play or pause button from a youTube video embedded on your page.

page with a youtube iframe and dev tools open showing the code

FrameLocator can be created with either page.frameLocator(selector) or locator.frameLocator(selector) method.

await page.frameLocator('iframe').locator('[aria-label="Pause"]').click()
Enter fullscreen mode Exit fullscreen mode

Just like with locators, Frame locators are also strict so this test will throw an error if it finds more than one iframe on the page.

Conclusion

And thats how you can use locators and frame locators to test iframes on a page. Have fun testing and as always reach out if you have any questions or comments.

Useful Links

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .