Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add argument --dryRunOnly to only run initial tests #3814

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ Config file: `"disableTypeChecks": false`

Configure a pattern that matches the files of which type checking has to be disabled. This is needed because Stryker will create (typescript) type errors when inserting the mutants in your code. Stryker disables type checking by inserting `// @ts-nocheck` atop those files and removing other `// @ts-xxx` directives (so they won't interfere with `@ts-nocheck`). The default setting allows these directives to be stripped from all JavaScript and friend files in `lib`, `src` and `test` directories. You can specify a different glob expression or set it to `false` to completely disable this behavior.

### `dryRunOnly` [`boolean`]

Default: `false`<br />
Command line: `--dryRunOnly`<br />
Config file: `"dryRunOnly": false`

Execute the initial test run only without doing actual mutation testing. Dry run only will still mutate your code before doing the dry run without those mutants being active, thus can be used to test that StrykerJS can run your test setup. This can be useful, for example, in CI pipelines.

### `dryRunTimeoutMinutes` [`number`]

Default: `5`<br />
Expand Down
5 changes: 5 additions & 0 deletions packages/api/schema/stryker-core.json
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@
"$ref": "#/definitions/dashboardOptions",
"default": {}
},
"dryRunOnly": {
"description": "Execute the initial test run only without doing actual mutation testing. Dry run only will still mutate your code before doing the dry run without those mutants being active, thus can be used to test that StrykerJS can run your test setup. This can be useful, for example, in CI pipelines.",
"type":"boolean",
"default": false
},
"eventReporter": {
"description": "The options for the event recorder reporter.",
"$ref": "#/definitions/eventRecorderOptions",
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/process/3-dry-run-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ export class DryRunExecutor {

public async execute(): Promise<Injector<MutationTestContext>> {
const testRunnerInjector = this.injector
.provideFactory(coreTokens.testRunnerFactory, createTestRunnerFactory)
.provideValue(coreTokens.testRunnerConcurrencyTokens, this.concurrencyTokenProvider.testRunnerToken$)
.provideFactory(coreTokens.testRunnerFactory, createTestRunnerFactory)
.provideFactory(coreTokens.testRunnerPool, createTestRunnerPool);
const testRunnerPool = testRunnerInjector.resolve(coreTokens.testRunnerPool);
const { result, timing } = await lastValueFrom(testRunnerPool.schedule(of(0), (testRunner) => this.executeDryRun(testRunner)));
Expand Down Expand Up @@ -110,6 +110,10 @@ export class DryRunExecutor {
}

private async executeDryRun(testRunner: TestRunner): Promise<DryRunCompletedEvent> {
if (this.options.dryRunOnly) {
this.log.info('Note: running the dry-run only. No mutations will be tested.');
}

const dryRunTimeout = this.options.dryRunTimeoutMinutes * 1000 * 60;
const project = this.injector.resolve(coreTokens.project);
const dryRunFiles = objectUtils.map(project.filesToMutate, (_, name) => this.sandbox.sandboxFileFor(name));
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/process/4-mutation-test-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export class MutationTestExecutor {
) {}

public async execute(): Promise<MutantResult[]> {
if (this.options.dryRunOnly) {
this.log.info('The dry-run has been completed successfully. No mutations have been executed.');
return [];
}

const mutantTestPlans = await this.planner.makePlan(this.mutants);
const { earlyResult$, runMutant$ } = this.executeEarlyResult(from(mutantTestPlans));
const { passedMutant$, checkResult$ } = this.executeCheck(runMutant$);
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/stryker-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export class StrykerCli {
'Configure a build command to run after mutating the code, but before mutants are tested. This is generally used to transpile your code before testing.' +
" Only configure this if your test runner doesn't take care of this already and you're not using just-in-time transpiler like `babel/register` or `ts-node`."
)
.option(
'--dryRunOnly',
'Execute the initial test run only, without doing actual mutation testing. Doing a dry run only can be used to test that StrykerJS can run your test setup, for example, in CI pipelines.'
)
.option(
'--checkers <listOfCheckersOrEmptyString>',
'A comma separated list of checkers to use, for example --checkers typescript',
Expand Down
1 change: 1 addition & 0 deletions packages/core/test/unit/config/options-validator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe(OptionsValidator.name, () => {
reportType: ReportType.Full,
},
disableTypeChecks: '{test,src,lib}/**/*.{js,ts,jsx,tsx,html,vue}',
dryRunOnly: false,
dryRunTimeoutMinutes: 5,
eventReporter: {
baseDir: 'reports/mutation/events',
Expand Down
18 changes: 18 additions & 0 deletions packages/core/test/unit/process/4-mutation-test-executor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,22 @@ describe(MutationTestExecutor.name, () => {
// Assert
expect(testInjector.logger.info).calledWithExactly('Done in %s.', '2 seconds, tops!');
});

it('should short circuit when dryRunOnly is enabled', async () => {
// Arrange
testInjector.options.dryRunOnly = true;
florisg-infosupport marked this conversation as resolved.
Show resolved Hide resolved
arrangeScenario();
const plan1 = mutantRunPlan({ id: '1' });
const plan2 = mutantRunPlan({ id: '2' });
mutantTestPlans.push(plan1, plan2);

// Act
const actualResults = await sut.execute();

// Assert
expect(mutantTestPlannerMock.makePlan).not.called;
expect(testRunner.mutantRun).not.called;
expect(checker.check).not.called;
expect(actualResults).empty;
});
});
1 change: 1 addition & 0 deletions packages/core/test/unit/stryker-cli.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe(StrykerCli.name, () => {
[['--checkers', ''], { checkers: [] }],
[['--checkerNodeArgs', '--inspect=1337 --gc'], { checkerNodeArgs: ['--inspect=1337', '--gc'] }],
[['--disableBail'], { disableBail: true }],
[['--dryRunOnly'], { dryRunOnly: true }],
[['--mutate', 'foo.js,bar.js'], { mutate: ['foo.js', 'bar.js'] }],
[['--reporters', 'foo,bar'], { reporters: ['foo', 'bar'] }],
[['--plugins', 'foo,bar'], { plugins: ['foo', 'bar'] }],
Expand Down