通过驱动程序执行的点击操作尽可能地模拟真实用户的行为,而JavaScript HTMLElement.click()
则执行click
事件的默认操作,即使该元素不可交互。
两者之间的区别在于:
驱动程序确保该元素可见,通过滚动将其滚动到视图中,并检查该元素是否可交互。
驱动程序将会报错:
- 当鼠标点击坐标处的元素不是目标元素或其后代时
- 当元素没有正面积或完全透明时
- 当元素是禁用的输入或按钮(属性/属性
disabled
为true
)时
- 当元素具有禁用鼠标指针(CSS
pointer-events
为none
)时
JavaScript HTMLElement.click()
将始终执行默认操作,或者如果该元素被禁用,则最多会静默失败。
如果该元素可以接受焦点,则期望驱动程序将其置于焦点上。
JavaScript HTMLElement.click()
不会这样做。
期望驱动程序发出所有事件(mousemove、mousedown、mouseup、click等),就像真实用户一样。
JavaScript HTMLElement.click()
仅会触发click
事件。
页面可能依赖于这些额外的事件,如果它们没有被触发,页面可能表现不同。
以下是使用Chrome的驱动程序为单击操作发出的事件:
mouseover {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mousemove {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mousedown {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
mouseup {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
click {target:#topic, clientX:222, clientY:343, isTrusted:true, ... }
这是使用JavaScript注入触发的事件:
click {target:#topic, clientX:0, clientY:0, isTrusted:false, ... }
JavaScript的.click()
触发的事件不可信任,默认动作可能不会被调用:
https://developer.mozilla.org/zh-CN/docs/Web/API/Event/isTrusted
https://googlechrome.github.io/samples/event-istrusted/index.html
请注意,一些驱动程序仍会生成不可信任的事件,如PhantomJS 2.1版本。
JavaScript的.click()
触发的事件没有点击的坐标信息。
clientX, clientY, screenX, screenY, layerX, layerY
属性都设置为0
。页面可能依赖这些属性,而导致行为不同。
在某些情况下,使用JavaScript的.click()
可以获取一些数据,但并不是在测试环境下。因为它不能模拟用户的行为,所以与测试的目的相悖。如果驱动程序中的点击失败,那么在同样的条件下真正的用户也很可能无法执行相同的点击。
在什么情况下驱动程序会无法点击我们期望它成功地点击一个元素?
由于延迟或过渡效果,目标元素尚未可见/可交互。
例如:
https://developer.mozilla.org/fr/docs/Web(下拉导航菜单)
http://materializecss.com/side-nav.html(侧边栏下拉菜单)
解决方法:
添加一个等待器以等待元素的可见性、最小大小或稳定位置:
browser.wait(ExpectedConditions.visibilityOf(elem), 5000);
browser.wait(ExpectedConditions.elementToBeClickable(elem), 5000);
browser.wait(function minimumWidth() {
return elem.getSize().then(size => size.width > 50);
}, 5000);
重试点击直到成功:
browser.wait(function clickSuccessful() {
return elem.click().then(() => true, (ex) => false);
}, 5000);
添加与动画/过渡持续时间相匹配的延迟:
browser.sleep(250);
一旦滚动到视图中,目标元素最终会被浮动元素覆盖:
驱动程序会自动将元素滚动到视图中以使其可见。如果页面包含浮动/固定元素(菜单、广告、页脚、通知、Cookie策略等),该元素可能最终被覆盖,不再可见或无法交互。
例如:https://twitter.com/?lang=en
解决方法:
将窗口大小设置为较大的值以避免滚动或浮动元素的干扰。
使用负数 Y
偏移量将鼠标悬停在元素上,然后单击它:
browser.actions()
.mouseMove(elem, {x: 0, y: -250})
.click()
.perform();
点击之前将元素滚动到窗口中心:
browser.executeScript(function scrollCenter(elem) {
var win = elem.ownerDocument.defaultView || window,
box = elem.getBoundingClientRect(),
dy = box.top - (win.innerHeight - box.height) / 2;
win.scrollTo(win.pageXOffset, win.pageYOffset + dy);
}, element);
element.click();
如果无法避免,请隐藏浮动元素:
browser.executeScript(function scrollCenter(elem) {
elem.style.display = 'none';
}, element);
click
或sendKeys
)可以正常工作,但并非总是如此。没有定位问题或其他异常,测试用例只是无法继续执行。日志显示操作已执行。有时使用Action
可以帮助解决问题。如果我手动点击元素(在测试用例停止后),一切都能正常工作。因此,在这种情况下我们转而使用原始JS。我已经有2年没有使用AngularJS了,所以现在可能会更好。 - Würgspaß