UNPKG

7.47 kBJavaScriptView Raw
1import os from 'os';
2import chalk from 'chalk';
3import { schema } from '@stryker-mutator/api/core';
4import { commonTokens } from '@stryker-mutator/api/plugin';
5import { TestStatus } from 'mutation-testing-metrics';
6import { tokens } from 'typed-inject';
7import { getEmojiForStatus, plural } from '../utils/string-utils.js';
8import { ClearTextScoreTable } from './clear-text-score-table.js';
9const { MutantStatus } = schema;
10export class ClearTextReporter {
11 constructor(log, options) {
12 this.log = log;
13 this.options = options;
14 this.out = process.stdout;
15 this.writeLine = (output) => {
16 this.out.write(`${output !== null && output !== void 0 ? output : ''}${os.EOL}`);
17 };
18 this.writeDebugLine = (input) => {
19 this.log.debug(input);
20 };
21 this.configConsoleColor();
22 }
23 configConsoleColor() {
24 if (!this.options.allowConsoleColors) {
25 chalk.level = 0; // All colors disabled
26 }
27 }
28 onMutationTestReportReady(_report, metrics) {
29 this.writeLine();
30 this.reportAllTests(metrics);
31 this.reportAllMutants(metrics);
32 this.writeLine(new ClearTextScoreTable(metrics.systemUnderTestMetrics, this.options).draw());
33 }
34 reportAllTests(metrics) {
35 function indent(depth) {
36 return new Array(depth).fill(' ').join('');
37 }
38 const formatTestLine = (test, state) => {
39 return `${this.color('grey', `${test.name}${test.location ? ` [line ${test.location.start.line}]` : ''}`)} (${state})`;
40 };
41 if (metrics.testMetrics) {
42 const reportTests = (currentResult, depth = 0) => {
43 var _a;
44 const nameParts = [currentResult.name];
45 while (!currentResult.file && currentResult.childResults.length === 1) {
46 currentResult = currentResult.childResults[0];
47 nameParts.push(currentResult.name);
48 }
49 this.writeLine(`${indent(depth)}${nameParts.join('/')}`);
50 (_a = currentResult.file) === null || _a === void 0 ? void 0 : _a.tests.forEach((test) => {
51 var _a, _b;
52 switch (test.status) {
53 case TestStatus.Killing:
54 this.writeLine(`${indent(depth + 1)}${this.color('greenBright', '✓')} ${formatTestLine(test, `killed ${(_a = test.killedMutants) === null || _a === void 0 ? void 0 : _a.length}`)}`);
55 break;
56 case TestStatus.Covering:
57 this.writeLine(`${indent(depth + 1)}${this.color('blueBright', '~')} ${formatTestLine(test, `covered ${(_b = test.coveredMutants) === null || _b === void 0 ? void 0 : _b.length}`)}`);
58 break;
59 case TestStatus.NotCovering:
60 this.writeLine(`${indent(depth + 1)}${this.color('redBright', '✘')} ${formatTestLine(test, 'covered 0')}`);
61 break;
62 }
63 });
64 currentResult.childResults.forEach((childResult) => reportTests(childResult, depth + 1));
65 };
66 reportTests(metrics.testMetrics);
67 }
68 }
69 reportAllMutants({ systemUnderTestMetrics }) {
70 this.writeLine();
71 let totalTests = 0;
72 const reportMutants = (metrics) => {
73 metrics.forEach((child) => {
74 var _a;
75 (_a = child.file) === null || _a === void 0 ? void 0 : _a.mutants.forEach((result) => {
76 var _a;
77 totalTests += (_a = result.testsCompleted) !== null && _a !== void 0 ? _a : 0;
78 switch (result.status) {
79 case MutantStatus.Killed:
80 case MutantStatus.Timeout:
81 case MutantStatus.RuntimeError:
82 case MutantStatus.CompileError:
83 this.reportMutantResult(result, this.writeDebugLine);
84 break;
85 case MutantStatus.Survived:
86 case MutantStatus.NoCoverage:
87 this.reportMutantResult(result, this.writeLine);
88 break;
89 default:
90 }
91 });
92 reportMutants(child.childResults);
93 });
94 };
95 reportMutants(systemUnderTestMetrics.childResults);
96 this.writeLine(`Ran ${(totalTests / systemUnderTestMetrics.metrics.totalMutants).toFixed(2)} tests per mutant on average.`);
97 }
98 statusLabel(mutant) {
99 const status = MutantStatus[mutant.status];
100 return this.options.clearTextReporter.allowEmojis ? `${getEmojiForStatus(status)} ${status}` : status.toString();
101 }
102 reportMutantResult(result, logImplementation) {
103 logImplementation(`[${this.statusLabel(result)}] ${result.mutatorName}`);
104 logImplementation(this.colorSourceFileAndLocation(result.fileName, result.location.start));
105 result
106 .getOriginalLines()
107 .split('\n')
108 .filter(Boolean)
109 .forEach((line) => {
110 logImplementation(chalk.red('- ' + line));
111 });
112 result
113 .getMutatedLines()
114 .split('\n')
115 .filter(Boolean)
116 .forEach((line) => {
117 logImplementation(chalk.green('+ ' + line));
118 });
119 if (result.status === MutantStatus.Survived) {
120 if (result.static) {
121 logImplementation('Ran all tests for this mutant.');
122 }
123 else if (result.coveredByTests) {
124 this.logExecutedTests(result.coveredByTests, logImplementation);
125 }
126 }
127 else if (result.status === MutantStatus.Killed && result.killedByTests && result.killedByTests.length) {
128 logImplementation(`Killed by: ${result.killedByTests[0].name}`);
129 }
130 else if (result.status === MutantStatus.RuntimeError || result.status === MutantStatus.CompileError) {
131 logImplementation(`Error message: ${result.statusReason}`);
132 }
133 logImplementation('');
134 }
135 colorSourceFileAndLocation(fileName, position) {
136 return [this.color('cyan', fileName), this.color('yellow', position.line), this.color('yellow', position.column)].join(':');
137 }
138 color(color, ...text) {
139 if (this.options.clearTextReporter.allowColor) {
140 return chalk[color](...text);
141 }
142 return text.join('');
143 }
144 logExecutedTests(tests, logImplementation) {
145 if (!this.options.clearTextReporter.logTests) {
146 return;
147 }
148 const testCount = Math.min(this.options.clearTextReporter.maxTestsToLog, tests.length);
149 if (testCount > 0) {
150 logImplementation('Tests ran:');
151 tests.slice(0, testCount).forEach((test) => {
152 logImplementation(` ${test.name}`);
153 });
154 const diff = tests.length - this.options.clearTextReporter.maxTestsToLog;
155 if (diff > 0) {
156 logImplementation(` and ${diff} more test${plural(diff)}!`);
157 }
158 logImplementation('');
159 }
160 }
161}
162ClearTextReporter.inject = tokens(commonTokens.logger, commonTokens.options);
163//# sourceMappingURL=clear-text-reporter.js.map
\No newline at end of file