如何通过Selenium点击Videogular封装的视频播放按钮?
首先咱们先搞定最紧急的NullPointerException——这个错误的根源非常明确:你在类成员变量里直接初始化了JavascriptExecutor js = (JavascriptExecutor) driver;,但此时driver还没被实例化(setup()方法是@BeforeClass注解,会在测试方法前执行,类初始化阶段driver还是null),所以js一直是null,调用js.executeScript自然就抛出空指针异常了。
第一步:修复NullPointerException
把JavascriptExecutor的初始化移到setup()方法里,确保driver实例化后再赋值:
public class TestClass { private WebDriver driver; private String baseUrl; LoginPageFactory loginPage; DashboardPageFactory dashboard; ViewSummaryPageFactory viewSummary; SimulationAnalysisPageFactory simulationAnalysis; JavascriptExecutor js; // 先声明,暂不初始化 @BeforeClass public void setup() { driver = new ChromeDriver(); baseUrl = "*****"; driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); driver.manage().window().maximize(); driver.get(baseUrl); loginPage = new LoginPageFactory(driver); dashboard = new DashboardPageFactory(driver); viewSummary = new ViewSummaryPageFactory(driver); simulationAnalysis = new SimulationAnalysisPageFactory(driver); js = (JavascriptExecutor) driver; // 这里初始化,此时driver已完成实例化 } // ... 其他测试代码 }
第二步:正确定位Videogular播放按钮并触发点击
你遇到的第二个问题是动态XPath无法稳定定位,而且原生JavaScript并没有document.getElementByxPath这个方法(不仅大小写错误,这个方法本身就不存在)。针对Videogular播放器,推荐两种可靠的解决方案:
方案1:用Selenium稳定定位元素,再通过JS点击
优先用相对定位找到目标视频的播放覆盖层,避免依赖动态生成的cdk-accordion-child-5这类ID。比如定位第二个视频的播放按钮:
// 定位第二个视频的播放覆盖层组件 WebElement playOverlay = driver.findElement(By.xpath("(//app-sensors-video)[2]//vg-overlay-play")); // 如果直接调用playOverlay.click()无效,再用JS触发点击 js.executeScript("arguments[0].click();", playOverlay);
方案2:直接在JS里用正确的XPath语法获取元素
如果一定要用JS执行XPath查询,需要使用原生的document.evaluate方法:
js.executeScript("const playBtn = document.evaluate('(//app-sensors-video)[2]//vg-overlay-play', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; playBtn.click();");
第三步:优化视频播放完成的判断逻辑
你当前的循环判断存在两个问题:Java中字符串相等必须用equals(),不能用!=;另外aria-valuenow通常返回纯数字字符串(比如"100"而非"100%"),需要调整判断逻辑:
String percentage = "0"; while (!percentage.equals("100")) { // 同样用相对定位第二个视频的进度条 WebElement scrubBar = driver.findElement(By.xpath("(//app-sensors-video)[2]//vg-scrub-bar/div")); percentage = scrubBar.getAttribute("aria-valuenow"); Thread.sleep(1000); // 加短休眠,避免频繁查询占用资源 if (percentage.equals("100")) { break; } }
额外建议:避免依赖动态ID
页面中的cdk-accordion-child-5这类ID是框架动态生成的,会随着页面结构变化而改变。建议用稳定的组件标签(比如app-sensors-video、vg-player)结合索引(//app-sensors-video)[n]来定位,这样即使页面有多个视频,也能精准定位第n个视频的元素。
内容的提问来源于stack exchange,提问作者Udi

