playwright-bdd
Version:
BDD Testing with Playwright runner
108 lines (93 loc) • 3.61 kB
text/typescript
/**
* Playwright reporter that generates different Cucumber reports.
*
* If there are multiple Cucumber reporters, they all generate the same Playwright messages,
* targeting messagesBuilder. The messagesBuilder performs heavy operations (like reading feature files),
* so we should build Cucumber messages only once. To achieve that, we keep track
* of the reporters count in teh reporters-registry and send Playwright events only from the first reporter.
* In onEnd, all reporters wait for messages to get built and emit them to the Cucumber reporter implementation.
*/
import {
FullConfig,
FullResult,
Reporter as PlaywrightReporter,
TestCase,
TestError,
TestResult,
} from '@playwright/test/reporter';
import BaseReporter, { InternalOptions } from './base';
import MessageReporter from './message';
import HtmlReporter from './html';
import JunitReporter from './junit';
import JsonReporter from './json';
import CustomReporter, { CustomReporterOptions } from './custom';
import { getConfigDirFromEnv } from '../../config/env';
import { getMessagesBuilder, registerReporter, unregisterReporter } from './reporters-registry';
const builtinReporters = {
html: HtmlReporter,
message: MessageReporter,
junit: JunitReporter,
'junit-modern': JunitReporter, // Deprecated alias for junit
json: JsonReporter,
} as const;
export type BuiltinReporters = typeof builtinReporters;
export type CucumberReporterOptions<T> = T extends keyof BuiltinReporters
? ConstructorParameters<BuiltinReporters[T]>[1]
: CustomReporterOptions;
export default class CucumberReporterAdapter<
T extends keyof BuiltinReporters | string,
> implements PlaywrightReporter {
private type: T;
private userOptions: CucumberReporterOptions<T>;
private reporter: BaseReporter;
private isFirstReporter: boolean;
constructor(fullOptions: { $type: T } & CucumberReporterOptions<T>) {
const { $type, ...userOptions } = fullOptions;
this.type = $type;
this.userOptions = userOptions as unknown as CucumberReporterOptions<T>;
this.reporter = this.createCucumberReporter();
this.isFirstReporter = registerReporter();
}
onBegin(config: FullConfig) {
if (this.isFirstReporter) getMessagesBuilder().onBegin(config);
}
printsToStdio() {
return this.reporter.printsToStdio();
}
onTestEnd(test: TestCase, result: TestResult) {
if (this.isFirstReporter) getMessagesBuilder().onTestEnd(test, result);
}
/**
* Error not related to any test, e.g. worker teardown.
*/
onError(error: TestError) {
if (this.isFirstReporter) getMessagesBuilder().onError(error);
}
async onEnd(result: FullResult) {
try {
if (this.isFirstReporter) await getMessagesBuilder().onEnd(result);
await getMessagesBuilder().finished;
await this.reporter.init();
getMessagesBuilder().emitMessages(this.reporter.eventBroadcaster);
await this.reporter.finished();
} finally {
unregisterReporter();
}
}
private createCucumberReporter() {
const internalOptions: InternalOptions = {
cwd: getConfigDirFromEnv(),
messagesBuilder: getMessagesBuilder(),
};
if (isBuiltInReporter(this.type)) {
const BuiltInReporter = builtinReporters[this.type];
return new BuiltInReporter(internalOptions, this.userOptions);
} else {
const reporterPath = this.type;
return new CustomReporter(internalOptions, reporterPath, this.userOptions);
}
}
}
function isBuiltInReporter(type: keyof BuiltinReporters | string): type is keyof BuiltinReporters {
return type in builtinReporters;
}