Skip to content

Selenium 4 : frameToBeAvailableAndSwitchToIt doesn’t seem to work

I am trying to work with a webpage in Selenium 4. The page has a few iframes and I am trying to wait for an iframe to load completely and then switch to it.

However, the code below doesn’t seem to work:

driver = new ChromeDriver(options);

driver.get("https://www.stagecoachliquor.com/online-store-1/Whiskey-c20954043");

WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(30));

wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.cssSelector("#TPASection_iw75naz9 > iframe")));

System.out.println(driver.getPageSource());

The system out just prints an empty HTML snippet below:

<html><head></head><body></body></html>

As a result, when I try to select any element after the switch, it fails. The iframe is loading alright in the chrome window which seems strange to me. I have tried implicit wait as well which did not work and had the same result.

After a few hours of debugging, I have not been able to identify the root cause. Any help is much appreciated.

Best, R

Answer

I’ve reproduced the issue.

This behavior looks like a selenium bug, because, when it switches to frame, the frame has no any product elements (they are loaded a few seconds later). But then, when I was in debug and all the products loaded, and a I call driver.getPageSource(), the result is <html><head></head><body></body></html>, and when I call this again, it loads the correct page source, but still the driver cannot find any element inside the iframe.

So, I’ve added a custom expected condition, which switches to frame and check if some element present for workaround this.

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.Test;

import static java.time.Duration.ofSeconds;

public class ChromeIframeTest {

    @Test
    public void test() {
        
        // I use https://github.com/bonigarcia/webdrivermanager lib for download chromedriver
        WebDriverManager.chromedriver().setup();
        ChromeOptions options = new ChromeOptions();
        WebDriver driver = new ChromeDriver(options);

        driver.get("https://www.stagecoachliquor.com/online-store-1/Whiskey-c20954043");

        WebDriverWait wait = new WebDriverWait(driver, ofSeconds(30));

        wait.until(
                frameToBeAvailableAndSwitchToItAndElementToBeAvailable(
                        By.cssSelector("#TPASection_iw75naz9 > iframe"),
                        By.cssSelector(".grid-product__shadow") // product in iframe
                )
        );
        System.out.println(driver.getPageSource());

        driver.quit();
    }

    // Custom expected condition
    public static ExpectedCondition<Boolean> frameToBeAvailableAndSwitchToItAndElementToBeAvailable(
            By frame, By frameElement) {
        return new ExpectedCondition<>() {
            private boolean isLoaded = false;

            @Override
            public Boolean apply(WebDriver driver) {
                if (ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame).apply(driver) != null) {
                    isLoaded = ExpectedConditions.presenceOfAllElementsLocatedBy(frameElement).apply(driver) != null;
                }
                if (!isLoaded) {
                    driver.switchTo().defaultContent();
                }
                return isLoaded;
            }

            @Override
            public String toString() {
                return String.format("element "%s" should present in frame "%s", is present: "%b"", frameElement.toString(), frame.toString(), isLoaded);
            }
        };
    }

}