我正在使用 Protractor 对 angular 2 项目进行端到端测试,我需要测试登录操作。这里的问题是,当单击登录按钮时,expect 语句仍然获取登录页面的 URL,就像主页一样。如果我等待,则测试成功。我在文档中的某处读到 Protractor 等待进程自动完成,所以,
- 是什么导致了这个错误?
- 如何在不显式使用
wait()
方法的情况下正确执行操作? - Protractor 是否有类似
fakeAsync
、async
或至少whenStable
的东西,比如 unit 测试?
这是我的测试用例
it("User successfully login",()=>{
browser.get(browser.baseUrl + '/account/login').then(() => {
return expect(browser.getCurrentUrl()).toBe(browser.baseUrl + "/account/login")
}).then(()=>{
element(by.tagName('input[type=text]')).sendKeys('username');
element(by.tagName('input[type=password]')).sendKeys('password');
element(by.css('button[type=submit]')).click().then(()=>{
return expect(browser.getCurrentUrl()).toBe(browser.baseUrl + "/home");
});
});
});
注意:
- 我有避免使用
browser.wait()
方法的说明。 - 登录按钮通过 API 向后端发送 http 请求。
解决方案[基于 Ernst 的解决方案]:
我解决了这个问题。我不知道它是否适用于其他场景,或者它是否是正确的方法。我加了
browser.wait(EC.urlContains(browser.baseUrl + "/account/login"), 10000);
browser.waitForAngularEnabled(false);
browser.wait(EC.urlContains(browser.baseUrl + "/home");
就在 click() 事件之后,它现在似乎可以正常工作。
最佳答案
错误原因:
click()
返回一个 promise , Protractor 等待解决。当登录请求被发送到服务器而不是主页加载时,它可能已经解决了。因此下一步的执行在页面加载之前开始。
为什么不wait()
:
我不确定,您是根据什么得到不使用 browser.wait()
的指令的。很可能你不应该使用 browser.sleep()
(因为那个命令总是过时的),但是如果你不想使用 browser.wait()
你的开发人员可能不会离开最初打开的 Angular 页面。
fakeAsync
、whenStable
等:
Protractor 在 browser.waitForAngular()
中默认使用 whenStable
,它总是在 promise 之后调用,只要您没有关闭 browser .waitForAngularEnabled(false)
...您只需要为非 Angular 页面关闭它,或者如果您的开发人员使用即持久的 Macrotasks,这将导致超时。
此外,由于 Selenium 控制流可能会在 2018 年 11 月被弃用 (read about here),因此 async/await
可用。
Read this important guide here还有一些further infos from protractor about it here
现在你的情况:
您不需要在您的情况下使用 then()
,因为您不需要立即解决 promise 。 expect()
将自动解决您的 promise ,因此那里不需要 then()
。
事实上 Protractor 逐行执行所有命令,就好像它们都包含在 then()
中一样,因此它会自动保持您的执行同步(只要您不启动异步任务通过在代码中使用 then()
。
所以这是我对您的代码的建议:
it("User successfully login",()=>{
var EC = protractor.ExpectedConditions; //or within onPrepare() of conf.js put global.EC = protractor.ExpectedConditions ... to make it everywhere available.
browser.get(browser.baseUrl + '/account/login');
//next line lets protractor wait max 5 seconds for your url to become, what you want.
browser.wait(EC.urlContains(browser.baseUrl + "/account/login"), 5000);
//additionally after the URL appeared, use this command to wait until the page is fully loaded.
browser.waitForAngular();
expect(browser.getCurrentUrl()).toBe(browser.baseUrl + "/account/login");
element(by.tagName('input[type=text]')).sendKeys('username');
element(by.tagName('input[type=password]')).sendKeys('password');
element(by.css('button[type=submit]')).click();
//next line lets protractor wait max 5 seconds for your url to become, what you want.
//as here a new page is loaded and the click()-promise is resolved before, use this:
browser.wait(EC.urlContains(browser.baseUrl + "/account/login"), 5000);
//additionally after the URL appeared, use this command to wait until the page is fully loaded.
browser.waitForAngular();
expect(browser.getCurrentUrl()).toBe(browser.baseUrl + "/home");
});
如果您现在超时,那么这是一个需要调试的单独问题。 检查this Protractor site for infos about timeouts并检查 this SO-Answer here了解如何调试超时。
关于angular - 在 Protractor 中单击按钮后如何等待 URL 加载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47195796/