Selenium 3切换Frame失效:如何无需重试机制修复?
Selenium Firefox驱动切换Frame后找不到元素的问题
登录后点击菜单选项卡中属于control frame的Switch按钮,页面加载完成后无法找到switchToProduction元素,驱动似乎仍关联旧的control frame。使用chromedriver及Selenium 2时一切正常,尝试过各种等待机制但问题未解决。
错误日志
console.warn: services.settings: Allow by setting MOZ_REMOTE_SETTINGS_DEVTOOLS=1 in the environment console.error: (new TypeError("lazy.AsyncShutdown.profileBeforeChange is undefined", "resource://services-settings/Database.sys.mjs", 599)) Exception in thread "main" org.openqa.selenium.TimeoutException: Expected condition failed: waiting for presence of any elements located by By.id: switchToProduction (tried for 5 second(s) with 500 milliseconds interval) at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:95) at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:272) at test.Test2.main(Test2.java:39) Caused by: org.openqa.selenium.NoSuchWindowException: Browsing context has been discarded Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03' System info: host: 'uk2prdd21846', ip: '127.0.0.1', os.name: 'Linux', os.arch: 'amd64', os.version: '3.10.0-1160.102.1.el7.x86_64', java.version: '1.8.0_341' Driver info: org.openqa.selenium.firefox.FirefoxDriver Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 115.4.0, javascriptEnabled: true, moz:accessibilityChecks: false, moz:buildID: 20231018093353, moz:geckodriverVersion: 0.33.0, moz:headless: false, moz:platformVersion: 3.10.0-1160.102.1.el7.x86_64, moz:processID: 8735, moz:profile: /tmp/rust_mozprofile11C1Wj, moz:shutdownTimeout: 60000, moz:useNonSpecCompliantPointerOrigin: false, moz:webdriverClick: true, moz:windowless: false, pageLoadStrategy: normal, platform: LINUX, platformName: LINUX, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify} Session ID: 769f8749-d169-4169-a0e0-bf4fcc429ea1 *** Element info: {Using=id, value=switchToProduction} at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:187) at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:122) at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49) at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:158) at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83) at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552) at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:353) at org.openqa.selenium.remote.RemoteWebDriver.findElementsById(RemoteWebDriver.java:376) at org.openqa.selenium.By$ById.findElements(By.java:180) at org.openqa.selenium.remote.RemoteWebDriver.findElements(RemoteWebDriver.java:311) at org.openqa.selenium.support.ui.ExpectedConditions$11.apply(ExpectedConditions.java:328) at org.openqa.selenium.support.ui.ExpectedConditions$11.apply(ExpectedConditions.java:325) at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:249)
使用环境
- Selenium 3.141.59
- geckodriver 0.33
- Firefox 113
测试代码
System.setProperty("webdriver.gecko.driver", "geckodriver"); // System.setProperty("webdriver.chrome.driver", "chromedriver"); FirefoxOptions options = new FirefoxOptions(); options.setLogLevel(Level.FINEST); WebDriver driver = new FirefoxDriver(options); driver.get("myurl"); //login driver.findElement(By.id("username")).sendKeys("user"); driver.findElement(By.name("password")).sendKeys("password"); driver.findElement(By.id("login")).click(); WebDriverWait wait = new WebDriverWait(driver, 5); //click Switch button from control frame driver.switchTo().defaultContent(); wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control"))); wait.until(ExpectedConditions.elementToBeClickable(By.id("switchToTest"))); driver.findElement(By.id("switchToTest")).click(); //check that after Switch button is pressed, Switch to Production button is present in "control" frame driver.switchTo().defaultContent(); wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control"))); wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.id("switchToProduction"))); driver.quit(); } }
pom.xml配置
<dependencies> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-api</artifactId> <version>3.141.59</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-support</artifactId> <version>3.141.59</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build>
解决方案
错误提示中的Browsing context has been discarded说明点击Switch按钮后,原有的control frame上下文已被销毁,Firefox重新渲染了frame,此时直接切换会关联旧的失效上下文。可以通过以下步骤修复:
- 延长等待时间并等待页面完全加载:点击Switch按钮后,先等待页面的
document.readyState变为complete,确保页面所有资源加载完成。 - 重新获取frame上下文:切换到defaultContent后,使用更长的等待时间确保新的control frame完全可用。
- 等待元素可见而非仅存在:
visibilityOfElementLocated比presenceOfAllElementsLocatedBy更可靠,能确保元素已渲染完成。
修改后的代码片段:
// 点击Switch按钮后,等待页面完全加载 wait.until(ExpectedConditions.jsReturnsValue("return document.readyState === 'complete'")); // 切换回默认上下文,重新获取control frame driver.switchTo().defaultContent(); // 延长等待时间到10秒,适配Firefox的渲染速度 WebDriverWait longerWait = new WebDriverWait(driver, 10); longerWait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("control"))); // 等待元素可见 longerWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("switchToProduction")));
另外,也可以尝试通过frame的其他属性(如name、xpath)定位,避免仅依赖id导致的定位问题。
内容的提问来源于stack exchange,提问作者mitzas
相关产品推荐
相关产品推荐

