I wrote some code to wrap the Playwright Page
to simplify a few operations. In one of my operations, I wanted to do something like typing and tabbing (this simulates the user behaviour better even if it is slower for Playwright so it's primarily to test that tab order works as expected).
The class to wrap would be something like this:
import { Locator, Page } from "@playwright/test";
class SimplePage {
constructor(private readonly page: Page) {}
async type(text: string): Promise<this> {
await this.page.keyboard.type(text);
return this;
}
async tab(): Promise<this> {
await this.page.keyboard.press("Tab");
return this;
}
}
At present the only way I can use this in my code is as follows:
await myPage.type(programName)
.then((p) => p.tab())
.then((p) => p.type(shortName))
.then((p) => p.tab());
or
await myPage.type(programName);
await myPage.tab();
await myPage.type(shortName);
await myPage.tab();
I was wondering if there's anyway to construct it so the following would work
await myPage
.type(programName)
.tab()
.type(shortName)
.tab();
You could give your SimplePage
class a promise
property, and at every call of tab
or text
, replace that promise with the new chained promise.
Finally, make SimplePage
a thenable, by defining a then
method. This way it will respond as expected to an await
operator:
class SimplePage {
private promise: Promise<void> = Promise.resolve();
constructor(private readonly page: Page) {}
type(text: string): SimplePage {
this.promise = this.promise.then(() => this.page.keyboard.type(text));
return this;
}
tab(): SimplePage {
this.promise = this.promise.then(() => this.page.keyboard.press("Tab"));
return this;
}
then(onFulfill: (value: any) => void, onReject: (error: any) => void) {
return this.promise.then(onFulfill, onReject);
}
}
PromiseLike
:The type declaration for then
would be:
class SimplePage implements PromiseLike<void> {
private promise: Promise<void> = Promise.resolve();
constructor(private readonly page: Page) {}
type(text: string): SimplePage {
this.promise = this.promise.then(() => this.page.keyboard.type(text));
return this;
}
tab(): SimplePage {
this.promise = this.promise.then(() => this.page.keyboard.press("Tab"));
return this;
}
then<TResult1, TResult2>(
onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined
): PromiseLike<TResult1|TResult2> {
return this.promise.then(onfulfilled, onrejected);
}
}