Асинхронный/ожидающий шаблон в транспортир

Я пытаюсь использовать async/await с protractor в TypeScript. Я следую примеру: 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/await с protractor?

Ответ 1

К сожалению, все эти ожидания не ожидаются - ваш код не будет синхронизирован должным образом. Есть несколько случаев, когда вы можете пропустить вставку в ожидании - но в большинстве случаев это необходимо, так как ожидается, что ваш график promises будет один за другим.

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

Так что подумайте, как приятный синтаксический сахар над обещанием цепочки: 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.

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 предпочтительнее с точки зрения удобочитаемости, но на языке, который требует, чтобы вы его использовали, нет ничего.