【问题标题】:async / await boilerplate in protractor量角器中的异步/等待样板
【发布时间】:2017-08-21 14:25:10
【问题描述】:

我正在尝试在TypeScript 中使用async / awaitprotractor。我在以下示例中进行操作:https://github.com/angular/protractor/tree/master/exampleTypescript/asyncAwait

在我的实验中运行良好。但是,我必须在每次与浏览器交互相关的调用中使用await

例如:

我有一个登录页面的页面对象:

login.ts:

import {browser, element, by, By, $, $$, ExpectedConditions} from "protractor";
import { DashboardPage } from "./dashboard";
export class LoginPage {
    usernameInput = element(by.id("username"));
    passwordInput = element(by.id("password"));
    loginButton = element(by.id("login_button"));

    async get() {
        await browser.get(login_url);
        return this;
    }

    async getTitle() {
        let title = await browser.getTitle();
        return title;
    }

    async typeUsername(username: string) {
        await this.usernameInput.sendKeys(username);
    }

    async typePassword(password: string) {
        await this.passwordInput.sendKeys(password);
    }

    async login() {
        await this.loginButton.click();
        return new DashboardPage();
    }
}

LoginSpec.ts:

import {browser, element, by, By, $, $$, ExpectedConditions} from "protractor";
import { LoginPage } from "../pages/login";
describe("Login Page", function() {

    beforeEach(() => {
        // login page is not an angular page.
        browser.ignoreSynchronization = true;
    });

    afterEach(() => {
        browser.ignoreSynchronization = false;
    });

    it("should go to dashboard page after successfully login", async (): Promise<any> => {
        let loginPage = new LoginPage();
        await loginPage.get();
        await loginPage.typeUsername(username);
        await loginPage.typePassword(password);
        let dashboard = await loginPage.login();
        expect(await dashboard.getTitle()).toEqual(`Dashboard`);
    });
});

在上面的测试规范中,我必须使用许多await 来调用浏览器交互。这为await 引入了很多样板。

问题是,有什么想法或方法可以减少样板文件吗?另外,这是将async / awaitprotractor 一起使用的正确方法吗?

【问题讨论】:

  • 第二个最好的选择是使用承诺链,它引入了更多的样板。我认为这是干净易读的代码。看到 await 会告诉您执行已在此处产生,因此全局状态可以在此处更改。
  • 如果你愿意使用纯业力,你可以选择使用节点光纤
  • 这对我来说似乎很好。无论如何,Imo await 并不是真正的样板代码。如果你的loginPage 方法需要时间来解决,你需要在那里的await 关键字来防止主线程阻塞。这样你的测试确实会运行得更快。
  • @TamasHegedus,是的。承诺链可能会引入更多样板。在这种情况下,我更喜欢await
  • @Randy,同意。我只是希望有某种方法可以从实际的测试代码中隐藏页面/浏览器的详细信息。例如,如果可能有一个注解告诉 js 引擎或 ts 转译器将 await 添加到所有 async 函数而不是显式使用 await,这将使编写实际测试代码更容易(无需记得使用await)。此外,它还避免了错误,以防有人忘记使用await

标签: typescript protractor


【解决方案1】:

很遗憾,如果没有所有这些等待 - 您的代码将无法正确同步。在某些情况下您可以省略粘贴 await - 但大多数情况下这是必要的,因为 awaits 会让您的 Promise 逐一安排。

Async/Await 仍然依赖于 Promises。所以你的等待代码的工作方式与此相同:

it("should go to dashboard page after successfully login", (): Promise<any> => {
    let loginPage = new LoginPage();
    return loginPage.get().then(() => {
        return loginPage.typeUsername(username);
    }).then(() => {
        return loginPage.typePassword(password);
    }).then(()=> {
        return loginPage.login();
    }).then((dashboard)=> {
        return expect(dashboard.getTitle()).toEqual(`Dashboard`);
    })
});

因此,将 await 视为一种优于 Promise 链接的语法糖: https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#option-1-use-classic-promise-chaining

但是有一种方法可以在不放置 awaits\thens\generators\callbacks 的情况下进行同步。它被称为“纤维”。不幸的是量角器不支持这个,但是 WebdriverIO 使用它来同步代码: https://www.facebook.com/ProtractorAngularJS/posts/1950761568515087

【讨论】:

    【解决方案2】:

    您可以在不使用await 的情况下轻松地按顺序运行它们,但我建议坚持使用 await 以提高可读性。

    这是您的代码在没有await 时的样子。

    import { LoginPage } from "../pages/login";
    
    describe("Login Page", function() {
    
        // mutable crap
    
        it("should go to dashboard page after successfully login", () => {
            const loginPage = new LoginPage();
    
            const asyncs = [
                () => loginPage.get(),
                () => loginPage.typeUsername(username),
                () => loginPage.typePassword(password),
                () => loginPage.login(),
                (dashboard: Dashboard) => dashboard.getTitle()
            ];
    
            const tilePromise = asyncs.reduce((promised, next) => promised.then(next));
    
            // note the return. this is required
            return titlePromise.then(dashboardTitle => {
                expect(dashboardTitle).toEqual('Dashboard');
            });
        });
    });
    

    同样,从可读性的角度来看,我认为await 更可取,但语言中没有任何内容要求您使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-01
      • 2018-07-08
      相关资源
      最近更新 更多