typescript - plantilla de async/await en protractor
Estoy intentando usar async/await con protractor en TypeScript. Estoy siguiendo el ejemplo en: https://github.com/angular/protractor/tree/master/exampleTypescript/asyncAwait
Está funcionando bien en mis experimentos. Sin embargo, tengo que usar await en todas las llamadas relacionadas con las interacciones del navegador.
Por ejemplo:
Tengo un objeto de página para una página de inicio de sesión:
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`);
});
});
En la especificación de prueba anterior, tengo que usar muchos await para todas las llamadas a interacciones con el navegador. Eso introduce mucha plantilla para await.
La pregunta es, ¿hay alguna idea o manera de reducir el código repetitivo? Además, ¿es esta la manera correcta de usar async/await con protractor?
Respuesta #1
Desafortunadamente, sin todos estos await, tu código no se sincronizará correctamente. Hay un par de casos en los que podrías omitir pegar await, pero en la mayoría de los casos esto es necesario, ya que los await hacen que tus promesas se programen una por una.
Async/Await todavía depende de las Promesas. Así que tu código con await funciona idénticamente a esto:
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`);
})
});
Así que considera `await` como un buen azúcar sintáctico sobre el encadenamiento de promesas: https://github.com/SeleniumHQ/selenium/wiki/WebDriverJs#option-1-use-classic-promise-chaining
Pero hay una manera de sincronizar sin usar awaits\thens\generators\callbacks. Se llama 'fibers'. Desafortunadamente, Protractor no lo soporta, pero WebdriverIO lo usa para sincronizar el código: https://www.facebook.com/ProtractorAngularJS/posts/1950761568515087
Respuesta #2
Puedes ejecutar fácilmente estos en secuencia sin usar await, pero recomiendo usar await por legibilidad.
Aquí se muestra cómo podría verse tu código sin 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');
});
});
});
De nuevo, creo que await es preferible desde el punto de vista de la legibilidad, pero no hay nada en el lenguaje que obligue a usarlo.
