Skip to content

Commit

Permalink
feat(test runner): Support for disable bail (#3074)
Browse files Browse the repository at this point in the history
Add support for disabling the test runner bail using `--disableBail` or `{ "disableBail": true }`. When bail is disabled, all failing tests are reported in `killedBy` and thus end up in the html report's "Tests" view.

**API** (all backward compatible):
* Change the `MutantRunResult` interface to support an array of tests in `killedBy` (`string` is still supported)
* Add `disabeBail` in both the `DryRunOptions` and the `MutantRunOptions`
* Support reporting an array of failed tests in `killedBy` in `toMutantRunResult` (while keeping it backward compatible)

**Test runners**
* Update all `TestRunner` plugins to support disabling bail.

**Core**
* Update the core to support this new interface
* Add new config option `--disableBail`
* Deprecate `jest.enableBail`, use `--disableBail` instead.
  • Loading branch information
Edgpaez authored Sep 1, 2021
1 parent 701d8b3 commit 0962232
Show file tree
Hide file tree
Showing 72 changed files with 3,210 additions and 810 deletions.
35 changes: 35 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,41 @@ Config file:

Settings for the `dashboard` [reporter](#reporters-string). See the [dashboard documentation](../General/dashboard.md) for more info.

### `disableBail` [`boolean`]

_Since v5.4_

Default: `false`<br />
Command: `--disableBail`<br />
Config file: `"disableBail": true`

Configure the test runner to report all failing tests when a mutant is killed instead of bailing after the first failing test. Bailing brings better performance, but you might be interested in the full report instead. This might be useful when using the "Tests" view to hunt for tests that don't kill a single mutant.

See the difference of bail vs no bail on StrykerJS's utils package (with `--concurrency 4`):

<table>
<tbody>
<tr>
<td>
<figure>
<img alt="With bail" src="./images/configuration-with-bail.png" />
<figcaption>With bail, in 2min 33s.</figcaption>
</figure>
</td>
<td>
<figure>
<img alt="Disable bail" src="./images/configuration-disable-bail.png" />
<figcaption>Disable bail, in 2 min 45s.</figcaption>
</figure>
</td>
</tr>
</tbody>
</table>

As you can see, when you disable bail, a lot more tests get the "Killing" status, meaning that they killed at least 1 mutant. This does come with a performance penalty of 12s in this example.

_Note: Disable bail needs to be supported by the test runner plugin in order to work. All official test runner plugins (`@stryker-mutator/xxx-runner`) support this feature._

### `disableTypeChecks` [`false | string`]

Default: `"{test,src,lib}/**/*.{js,ts,jsx,tsx,html,vue}"`<br />
Expand Down
Binary file added docs/images/configuration-disable-bail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/configuration-with-bail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { promises as fsPromises } from 'fs';
import { mutationTestReportSchema } from '@stryker-mutator/api/report';
import { expect } from 'chai';
import path from 'path';
import { calculateMetrics, MetricsResult, Metrics } from 'mutation-testing-metrics';
import { calculateMutationTestMetrics, MetricsResult, Metrics } from 'mutation-testing-metrics';
import { execSync, ExecException } from 'child_process';

interface PipedStdioSyncExecException extends ExecException {
Expand Down Expand Up @@ -50,14 +50,14 @@ export async function readMutationTestResult(eventResultDirectory = path.resolve
expect(mutationTestReportFile).ok;
const mutationTestReportContent = await fsPromises.readFile(path.resolve(eventResultDirectory, mutationTestReportFile || ''), 'utf8');
const report = JSON.parse(mutationTestReportContent) as mutationTestReportSchema.MutationTestResult;
const metricsResult = calculateMetrics(report.files);
const metricsResult = calculateMutationTestMetrics(report);
return metricsResult;
}

export async function readMutationTestingJsonResult(jsonReportFile = path.resolve('reports', 'mutation', 'mutation.json')) {
const mutationTestReportContent = await fsPromises.readFile(jsonReportFile, 'utf8');
const report = JSON.parse(mutationTestReportContent) as mutationTestReportSchema.MutationTestResult;
const metricsResult = calculateMetrics(report.files);
const metricsResult = calculateMutationTestMetrics(report);
return metricsResult;
}

Expand All @@ -73,7 +73,7 @@ export async function expectMetricsResult(expectedMetricsResult: Partial<Metrics
const actualMetricsResult = await readMutationTestResult();
const actualSnippet: Partial<WritableMetricsResult> = {};
for (const key in expectedMetricsResult) {
actualSnippet[key as keyof MetricsResult] = actualMetricsResult[key as keyof MetricsResult] as any;
actualSnippet[key as keyof MetricsResult] = actualMetricsResult.systemUnderTestMetrics[key as keyof MetricsResult] as any;
}
if (actualSnippet.metrics) {
if (typeof actualSnippet.metrics.mutationScore === 'number') {
Expand All @@ -88,15 +88,15 @@ export async function expectMetricsResult(expectedMetricsResult: Partial<Metrics

export async function expectMetricsJson(expectedMetrics: Partial<Metrics>) {
const actualMetricsResult = await readMutationTestingJsonResult();
expectActualMetrics(expectedMetrics, actualMetricsResult);
expectActualMetrics(expectedMetrics, actualMetricsResult.systemUnderTestMetrics);
}

/**
* @deprecated please use expectMetricsJson instead (and activate the json reporter)
*/
export async function expectMetrics(expectedMetrics: Partial<Metrics>) {
const actualMetricsResult = await readMutationTestResult();
expectActualMetrics(expectedMetrics, actualMetricsResult);
expectActualMetrics(expectedMetrics, actualMetricsResult.systemUnderTestMetrics);
}

export function expectActualMetrics(expectedMetrics: Partial<Metrics>, actualMetricsResult: MetricsResult) {
Expand Down
Loading

0 comments on commit 0962232

Please sign in to comment.