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
Advertisement
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); } }; } }