在Selenium 3中,如何在JavaScript中正确转换Object为WebElement/SearchContext?
Selenium v3 ShadowRoot类型转换报错解决方法
问题说明
在Java中通过(SearchContext)或(WebElement)强转JavascriptExecutor.executeScript返回的ShadowRoot对象可正常使用,但在使用as SearchContext(注:此处应为Kotlin语法,用户误标注为JavaScript)转换时,抛出异常:
Caused by: java.lang.ClassCastException: com.google.common.collect.Maps$TransformedEntriesMap cannot be cast to org.openqa.selenium.SearchContext
受限于Selenium v3版本,无法使用getShadowRoot()方法。
可行的Java代码
WebElement webElemHost = browser.findElement(By.xpath("//tagHere[@id='idHere']")); String strCSSSelector = "#idHere"; JavascriptExecutor js = (JavascriptExecutor) browser; SearchContext shadowRoot = (SearchContext) js.executeScript("return arguments[0].shadowRoot", webElemHost); WebElement shadowContent = shadowRoot.findElement(By.cssSelector(strCSSSelector));
报错代码(用户误标注为JavaScript,实际为Kotlin)
val webElemHost = browser.findElement(By.xpath("//tagHere[@id='idHere']")) val strCSSSelector = "#idHere" val js = browser as JavascriptExecutor val shadowRoot = js.executeScript("return arguments[0].shadowRoot", webElemHost) as SearchContext // 报错行 val shadowContent = shadowRoot.findElement(By.cssSelector(strCSSSelector))
原因分析
Selenium v3中,executeScript返回的ShadowRoot对象在JVM层面实际是TransformedEntriesMap类型,并非真正的SearchContext实例。Java的强转能生效是因为运行时允许隐式适配,但Kotlin的as转换会严格校验类型,因此抛出类型转换异常。
解决方案
方案1:直接通过JavaScript完成元素查找(推荐)
跳过类型转换,直接在executeScript中借助ShadowRoot查找元素,代码简洁且稳定:
val webElemHost = browser.findElement(By.xpath("//tagHere[@id='idHere']")) val strCSSSelector = "#idHere" val js = browser as JavascriptExecutor val shadowContent = js.executeScript( "return arguments[0].shadowRoot.querySelector(arguments[1])", webElemHost, strCSSSelector ) as WebElement
方案2:手动包装为SearchContext(不推荐)
若必须使用SearchContext的findElement方法,可借助Selenium内部类将返回的Map包装为ShadowRoot实例(依赖内部实现,存在兼容性风险):
import org.openqa.selenium.remote.RemoteWebElement import org.openqa.selenium.remote.ShadowRoot val webElemHost = browser.findElement(By.xpath("//tagHere[@id='idHere']")) val strCSSSelector = "#idHere" val js = browser as JavascriptExecutor val shadowRootMap = js.executeScript("return arguments[0].shadowRoot", webElemHost) as Map<*, *> val shadowRoot = ShadowRoot((webElemHost as RemoteWebElement).getWrappedDriver(), shadowRootMap) val shadowContent = shadowRoot.findElement(By.cssSelector(strCSSSelector))
内容的提问来源于stack exchange,提问作者PQ Co
相关产品推荐
相关产品推荐

