Selenium Java/Kotlin混用时JavascriptExecutor报类转换异常问题
问题背景
现有基于Selenium、Cucumber搭建的测试框架,大部分测试步骤定义采用Java编写,当前正在逐步将代码迁移至Kotlin,新增工具类统一使用Kotlin开发。
初始可正常运行的代码
初始版本SeleniumUtils.kt仅实现了判断页面元素是否存在的方法,代码如下:
import no.our.e2e.framework.selenium.Browser import org.openqa.selenium.By import org.openqa.selenium.JavascriptExecutor object SeleniumUtils { fun elementExistsOnPage(idSelector: String?): Boolean { return Browser.extendedDriver().findElements(By.id(idSelector)).size > 0 } }
该方法可在Java编写的步骤定义文件中正常调用,调用示例:
@When("^jeg go to the contakt page$") public void goToContaktPage() throws InterruptedException { if (SeleniumUtils.INSTANCE.elementExistsOnPage("messageDraftLink")) { goToContaktPageViaMessagebox(); } else { navigationPage.contakt.click(); } }
新增方法后的运行异常
在SeleniumUtils.kt中新增基于JavascriptExecutor实现的页面滚动至顶部方法后,代码如下:
import no.our.e2e.framework.selenium.Browser import org.openqa.selenium.By import org.openqa.selenium.JavascriptExecutor object SeleniumUtils { fun elementExistsOnPage(idSelector: String?): Boolean { return Browser.extendedDriver().findElements(By.id(idSelector)).size > 0 } fun scrollPage() { (Browser.extendedDriver() as JavascriptExecutor) .executeScript("window.scrollTo(0, -document.body.scrollHeight)") } }
在步骤定义中调用scrollPage()方法时抛出如下异常:
java.lang.ClassCastException: class no.our.e2e.framework.selenium.driver.ExtendedWebDriver cannot be cast to class org.openqa.selenium.JavascriptExecutor (no.our.e2e.framework.selenium.driver.ExtendedWebDriver and org.openqa.selenium.JavascriptExecutor are in unnamed module of loader 'app')
问题原因
该异常与Kotlin、Java混合编译无直接关联,属于Selenium依赖版本冲突导致的类型不匹配问题:
ExtendedWebDriver在编译时依赖的Selenium版本,与运行时classpath中实际加载的Selenium API版本不一致,导致运行时识别到的ExtendedWebDriver类未实现同路径下的JavascriptExecutor接口,触发类型强转失败。- 初始版本的方法未触发异常,是因为
elementExistsOnPage仅使用了WebDriver基础接口、By定位器等核心类,没有涉及JavascriptExecutor的类型强转,因此没有暴露依赖冲突问题,问题恰好出现在Kotlin迁移阶段属于时间上的巧合。 - Kotlin中的类型强转逻辑与Java完全一致,编译后同样会生成
checkcast字节码指令,不存在混编场景下特殊的强转逻辑差异。
解决方案
- 统一全项目Selenium依赖版本:使用
mvn dependency:tree(Maven项目)或gradle dependencies(Gradle项目)排查所有传递引入的Selenium依赖,排除版本不一致的selenium-api、selenium-remote-driver包,保证ExtendedWebDriver编译时使用的Selenium版本与运行时加载的版本完全一致。 - 优化滚动方法实现,增加类型判断兜底,同时修正滚动到顶部的JS脚本逻辑(原脚本使用负scrollHeight参数存在逻辑问题,滚动到顶部的正确坐标为(0,0)),优化后代码:
import org.openqa.selenium.Keys fun scrollPage() { val driver = Browser.extendedDriver() if (driver is JavascriptExecutor) { driver.executeScript("window.scrollTo(0, 0);") return } // 非JS执行器环境兜底:用快捷键滚动到顶部 driver.findElement(By.tagName("body")).sendKeys(Keys.CONTROL, Keys.HOME) }
内容的提问来源于stack exchange,提问作者user9347168
相关产品推荐
相关产品推荐

