Skip to content

Commit

Permalink
feat(reporter): configurable clear-text reporter (#4330)
Browse files Browse the repository at this point in the history
Add `reportTests`, `reportMutants` and `reportScoreTable` to `ClearTextReporterOptions`

- `reportTests` to log tests. When set to `true` this reporter will report a list of all tests with the amounts of mutants they killed (if any).
- `reportMutants` to log mutants. When set to `true` this reporter will report each `Survived` and `NoCoverage` mutant to the stdout and log other mutant states on debug log level.
- `reportScoreTable` to log the score table. When set to `true` this reporter will end with a summary table with a row per mutated file.

---------

Co-authored-by: Klugster <72280842+Klugster@users.noreply.github.com>
  • Loading branch information
C-Klug and collin-klug committed Oct 1, 2023
1 parent 47a3483 commit 74bcc74
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 7 deletions.
10 changes: 8 additions & 2 deletions docs/configuration.md
Expand Up @@ -96,7 +96,7 @@ Choose whether or not to clean the temp dir (which is ".stryker-tmp" inside the

### `clearTextReporter` [`ClearTextOptions`]

Default: `{ "allowColor": true, "allowEmojis": false, "logTests": true, "maxTestsToLog": 3 }`<br />
Default: `{ "allowColor": true, "allowEmojis": false, "logTests": true, "maxTestsToLog": 3, "reportTests": true, "reportMutants": true, "reportScoreTable": true }`<br />

Config file:

Expand All @@ -106,7 +106,10 @@ Config file:
"allowColor": true,
"allowEmojis": false,
"logTests": true,
"maxTestsToLog": 3
"maxTestsToLog": 3,
"reportTests": true,
"reportMutants": true,
"reportScoreTable": true
}
}
```
Expand Down Expand Up @@ -454,6 +457,9 @@ The `clear-text` reporter supports three additional config options:
- `allowColor` to use cyan and yellow in printing source file names and positions. This defaults to `true`, so specify as `clearTextReporter: { allowColor: false },` to disable if you must.
- `logTests` to log the names of unit tests that were run to allow mutants. By default, only the first three are logged. The config for your config file is: `clearTextReporter: { logTests: true },`
- `maxTestsToLog` to show more tests that were executed to kill a mutant when `logTests` is true. The config for your config file is: `clearTextReporter: { logTests: true, maxTestsToLog: 7 },`
- `reportTests` to log tests. When set to `true` this reporter will report a list of all tests with the amounts of mutants they killed (if any).
- `reportMutants` to log mutants. When set to `true` this reporter will report each `Survived` and `NoCoverage` mutant to the stdout, as well as log other mutant states on debug log level.
- `reportScoreTable` to log the score table. When set to `true` this reporter will end with a summary table with a row per mutated file.

The `dashboard` reporter sends a report to https://dashboard.stryker-mutator.io, enabling you to add a mutation score badge to your readme, as well as hosting your html report on the dashboard. It uses the [dashboard.\*](#dashboard-dashboardoptions) configuration options.

Expand Down
15 changes: 15 additions & 0 deletions packages/api/schema/stryker-core.json
Expand Up @@ -82,6 +82,21 @@
"type": "integer",
"minimum": 0,
"default": 3
},
"reportTests": {
"description": "Indicates whether or not to log all tests.",
"type": "boolean",
"default": true
},
"reportMutants": {
"description": "Indicates whether or not to log all mutants.",
"type": "boolean",
"default": true
},
"reportScoreTable": {
"description": "Indicates whether or not to log score table.",
"type": "boolean",
"default": true
}
}
},
Expand Down
17 changes: 12 additions & 5 deletions packages/core/src/reporters/clear-text-reporter.ts
Expand Up @@ -41,12 +41,19 @@ export class ClearTextReporter implements Reporter {

public onMutationTestReportReady(_report: schema.MutationTestResult, metrics: MutationTestMetricsResult): void {
this.writeLine();
this.reportAllTests(metrics);
this.reportAllMutants(metrics);
this.writeLine(new ClearTextScoreTable(metrics.systemUnderTestMetrics, this.options).draw());

if (this.options.clearTextReporter.reportTests) {
this.reportTests(metrics);
}
if (this.options.clearTextReporter.reportMutants) {
this.reportMutants(metrics);
}
if (this.options.clearTextReporter.reportScoreTable) {
this.writeLine(new ClearTextScoreTable(metrics.systemUnderTestMetrics, this.options).draw());
}
}

private reportAllTests(metrics: MutationTestMetricsResult) {
private reportTests(metrics: MutationTestMetricsResult) {
function indent(depth: number) {
return new Array(depth).fill(' ').join('');
}
Expand Down Expand Up @@ -83,7 +90,7 @@ export class ClearTextReporter implements Reporter {
}
}

private reportAllMutants({ systemUnderTestMetrics }: MutationTestMetricsResult): void {
private reportMutants({ systemUnderTestMetrics }: MutationTestMetricsResult): void {
this.writeLine();
let totalTests = 0;

Expand Down
3 changes: 3 additions & 0 deletions packages/core/test/helpers/producers.ts
Expand Up @@ -46,6 +46,9 @@ export const createClearTextReporterOptions = factoryMethod<ClearTextReporterOpt
allowEmojis: false,
logTests: true,
maxTestsToLog: 3,
reportTests: true,
reportMutants: true,
reportScoreTable: true,
}));

export type ConcurrencyTokenProviderMock = sinon.SinonStubbedInstance<I<ConcurrencyTokenProvider>> & {
Expand Down
3 changes: 3 additions & 0 deletions packages/core/test/unit/config/options-validator.spec.ts
Expand Up @@ -46,6 +46,9 @@ describe(OptionsValidator.name, () => {
allowEmojis: false,
logTests: true,
maxTestsToLog: 3,
reportTests: true,
reportMutants: true,
reportScoreTable: true,
},
commandRunner: {
command: 'npm test',
Expand Down
65 changes: 65 additions & 0 deletions packages/core/test/unit/reporters/clear-text-reporter.spec.ts
Expand Up @@ -57,6 +57,32 @@ describe(ClearTextReporter.name, () => {
]);
});

it('should not report the clear text table when reportScoreTable is not true', () => {
testInjector.options.clearTextReporter.reportScoreTable = false;

act({
files: {
'src/file.js': {
language: 'js',
mutants: [
{
id: '1',
location: { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } },
mutatorName: 'Block',
replacement: '{}',
status: MutantStatus.Killed,
},
],
source: 'console.log("hello world!")',
},
},
schemaVersion: '1.0',
thresholds: factory.mutationScoreThresholds({}),
});

expect(stdoutStub).not.calledWithMatch(sinon.match('File | % score | # killed | # timeout | # survived | # no cov | # errors |'));
});

it('should show emojis in table with enableConsoleEmojis flag', () => {
testInjector.options.clearTextReporter.allowEmojis = true;

Expand Down Expand Up @@ -246,6 +272,20 @@ describe(ClearTextReporter.name, () => {
expect(stdoutStub).calledWithMatch(sinon.match('[Survived] Math'));
});

it('should not report a Survived mutant to stdout when reportMutants is not true', async () => {
testInjector.options.clearTextReporter.reportMutants = false;
mutant.status = MutantStatus.Survived;
act(report);
expect(stdoutStub).not.calledWithMatch(sinon.match('[Survived] Math'));
});

it('should not report a NoCoverage mutant to stdout when reportMutants is not true', async () => {
testInjector.options.clearTextReporter.reportMutants = false;
mutant.status = MutantStatus.NoCoverage;
act(report);
expect(stdoutStub).not.calledWithMatch(sinon.match('[NoCoverage] Math'));
});

it('should report a Timeout mutant to stdout', async () => {
mutant.status = MutantStatus.Timeout;
act(report);
Expand Down Expand Up @@ -353,6 +393,31 @@ describe(ClearTextReporter.name, () => {
expect(stdoutStub).calledWithMatch(sinon.match(' ✘ quux should corge (covered 0)'));
});

it('should not report a list of tests if file names are unknown when reportTests is not true', () => {
testInjector.options.clearTextReporter.reportTests = false;
const report = factory.mutationTestReportSchemaMutationTestResult({
files: {
'foo.js': factory.mutationTestReportSchemaFileResult({
mutants: [
factory.mutationTestReportSchemaMutantResult({ killedBy: ['0'] }),
factory.mutationTestReportSchemaMutantResult({ coveredBy: ['1'] }),
],
}),
},
testFiles: {
'': factory.mutationTestReportSchemaTestFile({
tests: [
factory.mutationTestReportSchemaTestDefinition({ id: '0', name: 'foo should bar' }),
factory.mutationTestReportSchemaTestDefinition({ id: '1', name: 'baz should qux' }),
factory.mutationTestReportSchemaTestDefinition({ id: '2', name: 'quux should corge' }),
],
}),
},
});
act(report);
expect(stdoutStub).not.calledWithMatch(sinon.match('All tests'));
});

it('should report in the correct colors', () => {
testInjector.options.clearTextReporter.allowColor = true;
const report = factory.mutationTestReportSchemaMutationTestResult({
Expand Down

0 comments on commit 74bcc74

Please sign in to comment.