Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how chain works in BrowserInterface and chain to browser.eval #44085

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 30 additions & 5 deletions test/lib/browsers/base.ts
@@ -1,11 +1,18 @@
export type Event = 'request'

// This is the base Browser interface all browser
// classes should build off of, it is the bare
// methods we aim to support across tests
export class BrowserInterface {
/**
* This is the base Browser interface all browser
* classes should build off of, it is the bare
* methods we aim to support across tests
*
* They will always await last executed command.
* The interface is mutable - it doesn't have to be in sequece.
*
* You can manually await this interface to wait for completion of the last scheduled command.
*/
export class BrowserInterface implements PromiseLike<any> {
private promise: any
private then: any
then: PromiseLike<any>['then']
private catch: any

protected chain(nextCall: any): BrowserInterface {
Expand All @@ -18,6 +25,24 @@ export class BrowserInterface {
return this
}

/**
* This function will run in chain - it will wait for previous commands.
* But it won't have an effect on chain value and chain will still be green if this throws.
*/
protected chainWithReturnValue<T>(
callback: (...args: any[]) => Promise<T>
): Promise<T> {
return new Promise<T>((resolve, reject) => {
this.chain(async (...args: any[]) => {
try {
resolve(await callback(...args))
} catch (error) {
reject(error)
}
})
})
}

async setup(browserName: string, locale?: string): Promise<void> {}
async close(): Promise<void> {}
async quit(): Promise<void> {}
Expand Down
30 changes: 15 additions & 15 deletions test/lib/browsers/playwright.ts
Expand Up @@ -281,8 +281,8 @@ export class Playwright extends BrowserInterface {
return this.chain((el) => el.getAttribute(attr))
}

async hasElementByCssSelector(selector: string) {
return this.eval(`!!document.querySelector('${selector}')`) as any
hasElementByCssSelector(selector: string) {
return this.eval<boolean>(`!!document.querySelector('${selector}')`)
}

keydown(key: string): BrowserInterface {
Expand Down Expand Up @@ -344,19 +344,19 @@ export class Playwright extends BrowserInterface {
})
}

async eval(snippet) {
// TODO: should this and evalAsync be chained? Might lead
// to bad chains
return page
.evaluate(snippet)
.catch((err) => {
console.error('eval error:', err)
return null
})
.then(async (val) => {
await page.waitForLoadState()
return val
})
eval<T = any>(snippet): Promise<T> {
return this.chainWithReturnValue(() =>
page
.evaluate(snippet)
.catch((err) => {
console.error('eval error:', err)
return null
})
.then(async (val) => {
await page.waitForLoadState()
return val as T
})
)
}

async evalAsync(snippet) {
Expand Down