diff --git a/docs/src/test-reporter-api/class-reporter.md b/docs/src/test-reporter-api/class-reporter.md index ef16d278b7..5f62ac5530 100644 --- a/docs/src/test-reporter-api/class-reporter.md +++ b/docs/src/test-reporter-api/class-reporter.md @@ -140,6 +140,12 @@ Called on some global error, for example unhandled exception in the worker proce The error. +## optional async method: Reporter.onExit +* since: v1.25 + +Called before the test runner will terminate. Useful to perform work after all reporters have finished, for example open some UI. Fore regular reporting, you should use [`method: Reporter.onEnd`] instead. + + ## optional method: Reporter.onStdErr * since: v1.10 diff --git a/packages/playwright-test/src/reporters/html.ts b/packages/playwright-test/src/reporters/html.ts index f4e2546e48..76c49fe628 100644 --- a/packages/playwright-test/src/reporters/html.ts +++ b/packages/playwright-test/src/reporters/html.ts @@ -137,6 +137,7 @@ class HtmlReporter implements Reporter { private _options: HtmlReporterOptions; private _outputFolder!: string; private _open: string | undefined; + private _buildResult: { ok: boolean, singleTestId: string | undefined } | undefined; constructor(options: HtmlReporterOptions = {}) { this._options = options; @@ -189,12 +190,14 @@ class HtmlReporter implements Reporter { }); await removeFolders([this._outputFolder]); const builder = new HtmlBuilder(this._outputFolder); - const { ok, singleTestId } = await builder.build(this.config.metadata, reports); + this._buildResult = await builder.build(this.config.metadata, reports); + } + async onExit() { if (process.env.CI) return; - + const { ok, singleTestId } = this._buildResult!; const shouldOpen = this._open === 'always' || (!ok && this._open === 'on-failure'); if (shouldOpen) { await showHTMLReport(this._outputFolder, singleTestId); diff --git a/packages/playwright-test/src/reporters/multiplexer.ts b/packages/playwright-test/src/reporters/multiplexer.ts index 63720d1ab3..3d414d8a57 100644 --- a/packages/playwright-test/src/reporters/multiplexer.ts +++ b/packages/playwright-test/src/reporters/multiplexer.ts @@ -57,6 +57,11 @@ export class Multiplexer implements Reporter { await Promise.resolve().then(() => reporter.onEnd?.(result)).catch(e => console.error('Error in reporter', e)); } + async onExit() { + for (const reporter of this._reporters) + await Promise.resolve().then(() => reporter.onExit?.()).catch(e => console.error('Error in reporter', e)); + } + onError(error: TestError) { for (const reporter of this._reporters) wrap(() => reporter.onError?.(error)); diff --git a/packages/playwright-test/src/runner.ts b/packages/playwright-test/src/runner.ts index 2de30e8d0d..5a35b96cda 100644 --- a/packages/playwright-test/src/runner.ts +++ b/packages/playwright-test/src/runner.ts @@ -190,6 +190,7 @@ export class Runner { await new Promise(resolve => process.stdout.write('', () => resolve())); await new Promise(resolve => process.stderr.write('', () => resolve())); + await this._reporter.onExit?.(); return fullResult; } diff --git a/packages/playwright-test/types/testReporter.d.ts b/packages/playwright-test/types/testReporter.d.ts index 57c2ca83a6..b074712bce 100644 --- a/packages/playwright-test/types/testReporter.d.ts +++ b/packages/playwright-test/types/testReporter.d.ts @@ -379,6 +379,13 @@ export interface Reporter { */ onError?(error: TestError): void; + /** + * Called before the test runner will terminate. Useful to perform work after all reporters have finished, for example open + * some UI. Fore regular reporting, you should use + * [reporter.onEnd(result)](https://playwright.dev/docs/api/class-reporter#reporter-on-end) instead. + */ + onExit?(): Promise; + /** * Called when something has been written to the standard error in the worker process. * @param chunk Output chunk.