Selenium Webdriver Nodejs无法点击Shadow DOM内元素问题
问题根因
多层嵌套Shadow DOM场景下,Selenium WebDriver Node.js版会在把Shadow DOM内的元素序列化回Node.js运行上下文时丢失部分交互属性,直接调用WebElement实例的click()方法经常出现无响应、报元素不可交互的错误,和元素定位逻辑无关。
可行解决方案
方案1:浏览器上下文全链路穿透点击(稳定性最高,推荐)
完全绕开Node.js侧的WebElement序列化流程,所有Shadow Root查找、元素定位、点击逻辑全部在浏览器上下文内执行,适配任意嵌套层级的Shadow DOM,不存在跨边界兼容问题:
async function clickShadowDOMElement(driver) { const clickActionScript = ` // 查找第一层Shadow Host const firstLevelHost = document.querySelector("#container > div.sf_common_comp-Page__header > div > xweb-shellbar"); if (!firstLevelHost) return false; const firstLevelRoot = firstLevelHost.shadowRoot; // 查找第二层Shadow Host const secondLevelHost = firstLevelRoot.querySelector("#shellbarContainer"); if (!secondLevelHost) return false; const secondLevelRoot = secondLevelHost.shadowRoot; // 查找目标按钮并点击 const targetButton = secondLevelRoot.querySelector("div > div.ui5-shellbar-overflow-container.ui5-shellbar-overflow-container-left > button"); if (!targetButton) return false; targetButton.scrollIntoView({block: 'center'}); targetButton.click(); return true; `; // 加显式等待兜底,等元素可交互 await driver.wait(async () => { return driver.executeScript(clickActionScript); }, 5000, "Shadow DOM内目标元素点击超时"); } module.exports = clickShadowDOMElement;
方案2:保留原有分步定位逻辑,仅替换点击实现
如果需要保留现有分步获取Shadow Root、定位元素的代码结构,只需要把最后一步的原生click()调用替换为通过executeScript触发点击即可,规避序列化带来的交互失效问题:
async function getshadowDOM(driver) { // 获取第一层Shadow Root const shadowHost = await driver.findElement(By.css("#container > div.sf_common_comp-Page__header > div > xweb-shellbar"),3000); const shadowRoot = await driver.executeScript("return arguments[0].shadowRoot", shadowHost); // 获取第二层Shadow Root const shadowHost2nd = await shadowRoot.findElement(By.css("#shellbarContainer")); const shadowRoot2 = await driver.executeScript("return arguments[0].shadowRoot",shadowHost2nd); // 定位目标元素 const elem = await shadowRoot2.findElement(By.css("div > div.ui5-shellbar-overflow-container.ui5-shellbar-overflow-container-left > button")); // 替换原生点击,用JS触发交互 await driver.executeScript("arguments[0].scrollIntoView({block: 'center'}); arguments[0].click();", elem); } module.exports = getshadowDOM;
补充说明
- 针对UI5这类自定义组件库封装的按钮,若普通click事件触发无效,可以在脚本中按顺序派发
mousedown、mouseup、click事件模拟真实用户点击操作 - 不要使用Selenium旧版本(低于4.1.0)操作Shadow DOM,旧版本对Shadow Root的序列化支持存在已知bug,升级到4.1.0以上版本稳定性会明显提升
内容的提问来源于stack exchange,提问作者user2886528
相关产品推荐
相关产品推荐

