我维护一个复杂的 Angular (1.5.x) 应用程序,该应用程序正在使用 Protractor (2.5.x) 进行 E2E 测试。我在使用这种方法时遇到了问题,主要表现为测试看起来不稳定。在一个拉取请求中运行良好的测试在另一个请求中失败。这涉及简单的定位器,例如 by.linkTest(...)。我调试了失败的测试,应用程序位于正确的页面上,链接存在且可访问。
有没有其他人遇到过这些一致性问题?知道原因或解决方法吗?
我维护一个复杂的 Angular (1.5.x) 应用程序,该应用程序正在使用 Protractor (2.5.x) 进行 E2E 测试。我在使用这种方法时遇到了问题,主要表现为测试看起来不稳定。在一个拉取请求中运行良好的测试在另一个请求中失败。这涉及简单的定位器,例如 by.linkTest(...)。我调试了失败的测试,应用程序位于正确的页面上,链接存在且可访问。
有没有其他人遇到过这些一致性问题?知道原因或解决方法吗?
也就是说,您可以采取以下几项措施来解决我们共同无情的“脆弱”敌人:
selenium
和chromedriver
它使用带有一组内置或自定义预期条件的龙 。这可能是迄今为止解决问题的最可靠方法。不幸的是,这是特定于用例和问题的,您需要在有问题的地方修改您的实际测试。例如,如果您需要单击一个元素,请等待它可单击:browser.wait()
var EC = protractor.ExpectedConditions;
var elm = $("#myid");
browser.wait(EC.elementToBeClickable(elm), 5000);
elm.click();
最大化浏览器窗口(以避免随机元素不可见或不可点击错误)。把这个放到onPrepare()
:
browser.driver.manage().window().maximize();
browser.waitForAngular();
有问题的地方。我不知道为什么这会有所帮助,但我已经看到报告说它肯定有助于修复一个不稳定的测试。done()
回调。例如,这可能有助于在调用it()
之前不启动块done
beforeEach()
onPrepare()
函数返回一个承诺。这通常有助于确保为测试运行做好准备protractor-flake
包。更像是解决问题的快速解决方法还有其他针对特定问题的“技巧”,例如在文本框中输入缓慢、通过 JavaScript 进行点击等。
是的,我认为我们所有人都经历过这种脆弱的问题。
实际上,任何浏览器自动化工具都会出现片状问题。但是,在 Protractor 的情况下,这应该更少,因为 Protractor 具有内置的等待考虑,它仅在正确加载 dom 后才执行操作。但是,在少数情况下,如果您看到间歇性故障,您可能不得不使用一些显式等待。
我更喜欢使用一些智能等待方法,例如:
function waitForElementToClickable(locator) {
var domElement = element(by.css(locator)),
isClickable = protractor.ExpectedConditions.elementToBeClickable(domElement);
return browser.wait(isClickable, 2000)
.then(function () {
return domElement;
});
}
在将 2000 毫秒用作超时的情况下,您可以使用变量对其进行配置。有时,browser.sleep()
当我的智能等待都不起作用时,我也会选择。
我的团队一直在使用的一种解决方法是使用插件protractor-errors仅重新运行失败的测试。使用这个工具,我们可以在 2-3 次运行中识别出真正的失败和易碎测试。要添加插件,只需在 Protractor 配置的 onPrepare 函数底部添加一个 require 语句:
exports.config = {
...
onPrepare: function() {
require('protractor-errors');
}
}
使用插件运行测试时,您需要传递这些附加参数:
protractor config.js --params.errorsPath 'jasmineReports' --params.currentTime (timestamp) --params.errorRun (true or false)
如果您没有简单的方法来传递时间戳,还有一个 cli 工具将处理生成 currentTime。
根据我的经验,某些方法(例如sendKeys()
)并不总是在controlFlow()
队列中的预期时间触发,并且会导致测试变得不稳定。我通过专门将它们添加到controlFlow()
. 例如:
this.enterText = function(input, text) {
return browser.controlFlow().execute(function() {
input.sendKeys(text);
});
};