@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
JavaScript
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