在量角器中单击按钮后如何等待 URL 加载?

How to wait for URL to load after button click in protractor?

我正在 angular 2 项目上使用量角器进行端到端测试,我需要测试登录操作。这里的问题是,当单击登录按钮时,expect 语句仍然会获得登录页面的 URL 作为主页。如果我等待,则测试成功。我在文档中的某个地方读到量角器等待进程自动完成,所以,

  1. 导致此错误的原因是什么?
  2. 如何在不显式使用 wait() 方法的情况下正确执行操作?
  3. 量角器是否有类似于 fakeAsyncasync 或至少 whenStable 的单位 测试?

这是我的测试用例

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");
        });

    });
});

注:

  1. 我有避免使用 browser.wait() 方法的说明。
  2. 登录按钮通过API向后端发送http请求。

解决方案[基于 Ernst 的解决方案]:

我解决了这个问题。我不知道它是否适用于其他场景,或者它是否是正确的方法。我添加了

browser.wait(EC.urlContains(browser.baseUrl + "/account/login"), 10000);
browser.waitForAngularEnabled(false);
browser.wait(EC.urlContains(browser.baseUrl + "/home");

就在 click() 事件之后,它现在似乎可以正常工作。

错误原因:

click() returns 一个promise,量角器等待解决。当登录请求被发送到服务器而不是主页加载时,它可能已经解决了。因此下一步的执行在页面加载之前开始。

为什么不wait():

我不确定,您根据什么得到不使用 browser.wait() 的指示。很可能你不应该使用 browser.sleep()(因为该命令总是过时的),但如果你不想使用 browser.wait(),你的开发人员可能不会离开最初打开的 Angular 页面.

fakeAsyncwhenStable 等等:

Protractor 在 browser.waitForAngular() 中默认使用 whenStable,它总是在承诺之后调用,只要你没有关闭 browser.waitForAngularEnabled(false)... 你只需要关闭非 angular 页面,或者如果您的开发人员使用即持久的 Macrotasks,这将导致超时。

此外,由于 Selenium 控制流可能会在 2018 年 11 月被弃用 (read about here),因此 async/await 可用。 Read this important guide here and also some further infos from protractor about it here

现在你的情况是:

您不需要在您的案例中使用 then(),因为您不需要立即解决承诺。 expect() 会自动解决你的承诺,所以那里不需要 then()

事实上 Protractor 逐行执行所有命令,就好像它们都包含在 then()s 中一样,因此它会自动保持您的执行同步(只要您不通过使用 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 and check 如何调试超时。