UNPKG

@serenity-js/playwright-test

Version:

Serenity/JS test runner adapter for Playwright Test, combining Playwright's developer experience with the advanced reporting and automation capabilities of Serenity/JS

112 lines 4.96 kB
import { Clock, Duration, Serenity, Timestamp } from '@serenity-js/core'; import { TestRunFinished, TestRunFinishes, TestRunStarts } from '@serenity-js/core/events'; import { ExecutionFailedWithError, ExecutionSuccessful, } from '@serenity-js/core/model'; import { PlaywrightErrorParser } from './PlaywrightErrorParser.js'; import { PlaywrightEventBuffer } from './PlaywrightEventBuffer.js'; import { PlaywrightTestSceneIdFactory } from './PlaywrightTestSceneIdFactory.js'; /** * Serenity/JS reporter that receives notifications from Playwright Test and emits them as * Serenity/JS [Serenity/JS domain events](https://serenity-js.org/api/core-events/class/DomainEvent/) which can be used by * Serenity/JS [stage crew members](https://serenity-js.org/api/core/interface/StageCrewMember/). */ export class SerenityReporterForPlaywrightTest { errorParser = new PlaywrightErrorParser(); sceneIdFactory; serenity; unhandledError; eventBuffer = new PlaywrightEventBuffer(); suiteTestCounts = new Map(); /** * @param config */ constructor(config) { this.sceneIdFactory = new PlaywrightTestSceneIdFactory(); this.serenity = new Serenity(new Clock(), process.cwd(), this.sceneIdFactory); this.serenity.configure(config); } onBegin(config, suite) { this.eventBuffer.configure(config); this.serenity.announce(new TestRunStarts(this.serenity.currentTime())); this.countTestsPerSuite(suite); } countTestsPerSuite(suite) { suite.allTests().forEach(test => { let currentSuite = test.parent; while (currentSuite) { const count = this.suiteTestCounts.get(currentSuite) ?? 0; this.suiteTestCounts.set(currentSuite, count + 1); currentSuite = currentSuite.parent; } }); } onTestBegin(test, result) { this.eventBuffer.appendTestStart(test, result); } // TODO might be nice to support that by emitting TestStepStarted / Finished // onStepBegin(test: TestCase, _result: TestResult, step: TestStep): void { // // console.log('>> onStepBegin'); // } // todo: add stdout -> Log https://github.com/microsoft/playwright/blob/main/packages/playwright/src/reporters/list.ts#L67 // onStepEnd(test: TestCase, _result: TestResult, step: TestStep): void { // // console.log('>> onStepEnd'); // } onTestEnd(test, result) { const pendingAfterAllHooks = this.countPendingAfterAllHooks(test); if (test.retries > 0) { this.eventBuffer.appendRetryableSceneEvents(test, result); } this.eventBuffer.appendCrashedWorkerEvents(test, result); this.eventBuffer.appendSceneEvents(test, result); if (pendingAfterAllHooks === 0) { this.eventBuffer.appendSceneFinishedEvent(test, result); const events = this.eventBuffer.flush(test, result); this.serenity.announce(...events); } else { this.eventBuffer.deferAppendingSceneFinishedEvent(test, result); } } countPendingAfterAllHooks(test) { let currentSuite = test.parent; const pendingAfterAllHooks = []; while (currentSuite) { const remainingSuites = (this.suiteTestCounts.get(currentSuite) || 0) - 1; this.suiteTestCounts.set(currentSuite, remainingSuites); if (remainingSuites === 0 && currentSuite['_hooks'].some((hook) => hook.type === 'afterAll')) { pendingAfterAllHooks.push(currentSuite); } currentSuite = currentSuite.parent; } return pendingAfterAllHooks.length; } onError(error) { if (!this.unhandledError) { this.unhandledError = this.errorParser.errorFrom(error); } } async onEnd(fullResult) { const deferredEvents = this.eventBuffer.flushAllDeferred(); this.serenity.announce(...deferredEvents); const fullDuration = Duration.ofMilliseconds(Math.round(fullResult.duration)); const endTime = new Timestamp(fullResult.startTime).plus(fullDuration); this.serenity.announce(new TestRunFinishes(endTime)); try { await this.serenity.waitForNextCue(); const outcome = this.unhandledError ? new ExecutionFailedWithError(this.unhandledError) : new ExecutionSuccessful(); this.serenity.announce(new TestRunFinished(outcome, endTime)); } catch (error) { this.serenity.announce(new TestRunFinished(new ExecutionFailedWithError(error), endTime)); throw error; } } // TODO emit a text artifact with stdout // reporter.onStdErr(chunk, test, result) // reporter.onStdOut(chunk, test, result) printsToStdio() { return true; } } //# sourceMappingURL=SerenityReporterForPlaywrightTest.js.map