Skip to content

Commit

Permalink
fix(playwright): teardown when global quit force terminates browser
Browse files Browse the repository at this point in the history
  • Loading branch information
kwonoj committed Dec 12, 2023
1 parent ed12b55 commit aacd8fc
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 10 deletions.
3 changes: 2 additions & 1 deletion run-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ ${ENDGROUP}`)
// If environment is CI and if this test execution is failed after retry, preserve test traces
// to upload into github actions artifacts for debugging purpose
const shouldPreserveTracesOutput =
process.env.CI && isRetry && isChildExitWithNonZero
(process.env.CI && isRetry && isChildExitWithNonZero) ||
process.env.PRESERVE_TRACES_OUTPUT
if (!shouldPreserveTracesOutput) {
await fsp
.rm(
Expand Down
25 changes: 16 additions & 9 deletions test/lib/browsers/playwright.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,25 @@ let websocketFrames: Array<{ payload: string | Buffer }> = []

const tracePlaywright = process.env.TRACE_PLAYWRIGHT

// loose global to register teardown functions before quitting the browser instance.
// This is due to `quit` can be called anytime outside of BrowserInterface's lifecycle,
// which can create corrupted state by terminating the context.
// [TODO] global `quit` might need to be removed, instead should introduce per-instance teardown
const pendingTeardown = []
export async function quit() {
await Promise.all(pendingTeardown.map((fn) => fn()))
await context?.close()
await browser?.close()
context = undefined
browser = undefined
}

async function teardown(tearDownFn: () => Promise<void>) {
pendingTeardown.push(tearDownFn)
await tearDownFn()
pendingTeardown.splice(pendingTeardown.indexOf(tearDownFn), 1)
}

interface ElementHandleExt extends ElementHandle {
getComputedCss(prop: string): Promise<string>
text(): Promise<string>
Expand All @@ -38,7 +50,6 @@ export class Playwright extends BrowserInterface {
private eventCallbacks: Record<Event, Set<(...args: any[]) => void>> = {
request: new Set(),
}

private async initContextTracing(
url: string,
page: Page,
Expand All @@ -50,7 +61,7 @@ export class Playwright extends BrowserInterface {

try {
// Clean up if any previous traces are still active
await this.teardownTracing()
await teardown(this.teardownTracing.bind(this))

await context.tracing.start({
screenshots: true,
Expand All @@ -60,7 +71,7 @@ export class Playwright extends BrowserInterface {
this.activeTrace = encodeURIComponent(url)

page.on('close', async () => {
await this.teardownTracing()
await teardown(this.teardownTracing.bind(this))
})
} catch (e) {
this.activeTrace = undefined
Expand All @@ -87,6 +98,7 @@ export class Playwright extends BrowserInterface {
path: traceOutputPath,
})
} catch (e) {
require('console').warn('Failed to teardown playwright tracing', e)
} finally {
this.activeTrace = undefined
}
Expand Down Expand Up @@ -128,16 +140,14 @@ export class Playwright extends BrowserInterface {
if (browser) {
if (contextHasJSEnabled !== javaScriptEnabled) {
// If we have switched from having JS enable/disabled we need to recreate the context.
await teardown(this.teardownTracing.bind(this))
await context?.close()
context = await browser.newContext({
locale,
javaScriptEnabled,
ignoreHTTPSErrors,
...device,
})
context.once('close', async () => {
await this.teardownTracing()
})
contextHasJSEnabled = javaScriptEnabled
}
return
Expand All @@ -150,9 +160,6 @@ export class Playwright extends BrowserInterface {
ignoreHTTPSErrors,
...device,
})
context.once('close', async () => {
await this.teardownTracing()
})
contextHasJSEnabled = javaScriptEnabled
}

Expand Down

0 comments on commit aacd8fc

Please sign in to comment.