C#中Selenium TouchActions触摸操作无响应问题求解
问题成因
- 核心原因是Chrome 75及以上版本配套的ChromeDriver默认开启W3C WebDriver标准协议,Selenium 3.141.0自带的
TouchActions、RemoteTouchScreen实现完全基于旧版JSON Wire Protocol的非标准触摸接口,这类接口在W3C模式下执行不会返回错误,但ChromeDriver会直接静默丢弃对应的操作指令,不会实际下发到渲染页面。 - 你自定义的
ChromeDriverWithTouchScreen虽然实现了IHasTouchScreen接口,但TouchActions类本身没有做W3C模式下的触摸输入源适配,实际执行SingleTap时发送的是普通鼠标点击事件。而开启移动端模拟的站点大多只监听touchstart/touchend/tap类触摸事件,不会响应鼠标事件,最终表现就是代码正常跑完、页面完全没反应。 - 更换测试站点、Selenium和ChromeDriver小版本无法解决问题的逻辑很简单:只要ChromeDriver版本≥75,默认开启W3C模式的逻辑就存在,而Selenium 3.x全版本都没有对W3C标准下的触摸操作做官方适配,怎么换小版本都绕不开这个兼容问题。
解决方案
根据项目实际情况选以下任意一种方案即可:
方案1:强制ChromeDriver走旧版协议(Selenium 3.x场景下改动最小)
在初始化ChromeOptions时增加配置关闭W3C模式,让旧版触摸接口恢复正常可用,修改后的初始化代码如下:
var chromeOptions = new ChromeOptions(); chromeOptions.EnableMobileEmulation("iPhone X"); // 新增配置强制关闭W3C模式 chromeOptions.AddAdditionalCapability("w3c", false, true); var chromeDriver = new ChromeDriverWithTouchScreen(chromeOptions); // 后续原有触摸操作逻辑不需要做任何改动
注意:该方案仅支持ChromeDriver 103及以下版本,更高版本的ChromeDriver已经完全移除了旧版JSON Wire Protocol的支持,加了这个配置也会启动失败。
方案2:通过JS派发原生触摸事件(全版本兼容,无依赖限制)
直接弃用兼容性差的TouchActions,通过执行JavaScript向目标元素派发标准触摸事件,模拟点按操作,示例封装代码如下:
/// <summary> /// 模拟对指定元素的单指点按操作 /// </summary> /// <param name="driver">WebDriver实例</param> /// <param name="element">待点击的目标元素</param> public static void TouchTap(IWebDriver driver, IWebElement element) { var jsExecutor = (IJavaScriptExecutor)driver; const string tapScript = @" const target = arguments[0]; const rect = target.getBoundingClientRect(); const touchItem = new Touch({ identifier: Date.now(), target: target, clientX: rect.left + rect.width / 2, clientY: rect.top + rect.height / 2, radiusX: 2.5, radiusY: 2.5, rotationAngle: 10, force: 1 }); target.dispatchEvent(new TouchEvent('touchstart', { cancelable: true, bubbles: true, touches: [touchItem], targetTouches: [touchItem], changedTouches: [touchItem] })); target.dispatchEvent(new TouchEvent('touchend', { cancelable: true, bubbles: true, touches: [], targetTouches: [], changedTouches: [touchItem] })); "; jsExecutor.ExecuteScript(tapScript, element); }
使用时直接替换原来的TouchActions逻辑即可:
var element = chromeDriver.FindElement(By.XPath("//someButton")); TouchTap(chromeDriver, element);
该方案不存在协议兼容问题,所有支持移动端模拟的ChromeDriver版本都能正常运行,后续要实现长按、滑动等操作也可以基于同样的逻辑扩展。
方案3:升级Selenium到4.x版本,使用官方标准API
如果项目允许升级依赖,直接把Selenium.WebDriver升级到4.x以上版本,弃用旧的TouchActions和自定义驱动类,使用W3C标准的Actions API绑定触摸指针源实现点按,示例代码如下:
var chromeOptions = new ChromeOptions(); chromeOptions.EnableMobileEmulation("iPhone X"); // 不需要自定义驱动类,直接用官方ChromeDriver即可 var chromeDriver = new ChromeDriver(chromeOptions); chromeDriver.Navigate().GoToUrl("https://someUrl"); var element = chromeDriver.FindElement(By.XPath("//someButton")); // 初始化触摸类型的指针输入设备 var touchPointer = new PointerInputDevice(PointerKind.Touch); var actionSeq = new ActionSequence(touchPointer); // 依次执行移动到元素中心、按下、抬起动作,完成点按 actionSeq.AddAction(touchPointer.CreatePointerMove(element, 0, 0, TimeSpan.FromMilliseconds(100))); actionSeq.AddAction(touchPointer.CreatePointerDown(MouseButton.Left)); actionSeq.AddAction(touchPointer.CreatePointerUp(MouseButton.Left)); chromeDriver.PerformActions(new List<ActionSequence> { actionSeq });
该方案是Selenium官方推荐的标准实现,兼容所有最新版本的ChromeDriver,稳定性最好。
内容的提问来源于stack exchange,提问作者Penzinandreas
相关产品推荐
相关产品推荐

