UNPKG

3.42 kBPlain TextView Raw
1import { MutantResult, schema, StrykerOptions } from '@stryker-mutator/api/core';
2import { Logger } from '@stryker-mutator/api/logging';
3import { commonTokens, PluginKind } from '@stryker-mutator/api/plugin';
4import { DryRunCompletedEvent, MutationTestingPlanReadyEvent, Reporter } from '@stryker-mutator/api/report';
5import { MutationTestMetricsResult } from 'mutation-testing-metrics';
6import { tokens } from 'typed-inject';
7
8import { coreTokens, PluginCreator } from '../di/index.js';
9
10import { StrictReporter } from './strict-reporter.js';
11
12export class BroadcastReporter implements StrictReporter {
13 public static readonly inject = tokens(commonTokens.options, coreTokens.pluginCreator, commonTokens.logger);
14
15 public readonly reporters: Record<string, Reporter>;
16 constructor(private readonly options: StrykerOptions, private readonly pluginCreator: PluginCreator, private readonly log: Logger) {
17 this.reporters = {};
18 this.options.reporters.forEach((reporterName) => this.createReporter(reporterName));
19 this.logAboutReporters();
20 }
21
22 private createReporter(reporterName: string): void {
23 if (reporterName === 'progress' && !process.stdout.isTTY) {
24 this.log.info('Detected that current console does not support the "progress" reporter, downgrading to "progress-append-only" reporter');
25 reporterName = 'progress-append-only';
26 }
27 this.reporters[reporterName] = this.pluginCreator.create(PluginKind.Reporter, reporterName);
28 }
29
30 private logAboutReporters(): void {
31 const reporterNames = Object.keys(this.reporters);
32 if (reporterNames.length) {
33 if (this.log.isDebugEnabled()) {
34 this.log.debug(`Broadcasting to reporters ${JSON.stringify(reporterNames)}`);
35 }
36 } else {
37 this.log.warn("No reporter configured. Please configure one or more reporters in the (for example: reporters: ['progress'])");
38 }
39 }
40
41 private broadcast<TMethod extends keyof Reporter>(methodName: TMethod, ...eventArgs: Parameters<Required<Reporter>[TMethod]>): Promise<void[]> {
42 return Promise.all(
43 Object.entries(this.reporters).map(async ([reporterName, reporter]) => {
44 if (reporter[methodName]) {
45 try {
46 await (reporter[methodName] as (...args: Parameters<Required<Reporter>[TMethod]>) => Promise<void> | void)!(...eventArgs);
47 } catch (error) {
48 this.handleError(error, methodName, reporterName);
49 }
50 }
51 })
52 );
53 }
54
55 public onDryRunCompleted(event: DryRunCompletedEvent): void {
56 void this.broadcast('onDryRunCompleted', event);
57 }
58 public onMutationTestingPlanReady(event: MutationTestingPlanReadyEvent): void {
59 void this.broadcast('onMutationTestingPlanReady', event);
60 }
61
62 public onMutantTested(result: MutantResult): void {
63 void this.broadcast('onMutantTested', result);
64 }
65
66 public onAllMutantsTested(results: MutantResult[]): void {
67 void this.broadcast('onAllMutantsTested', results);
68 }
69
70 public onMutationTestReportReady(report: schema.MutationTestResult, metrics: MutationTestMetricsResult): void {
71 void this.broadcast('onMutationTestReportReady', report, metrics);
72 }
73
74 public async wrapUp(): Promise<void> {
75 await this.broadcast('wrapUp');
76 }
77
78 private handleError(error: unknown, methodName: string, reporterName: string) {
79 this.log.error(`An error occurred during '${methodName}' on reporter '${reporterName}'.`, error);
80 }
81}