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 3 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.

### `dryRun` [`boolean`]

Default: `false`<br />
Command line: `--dryRun`<br />
Config file: `"dryRun": 5`
florisg-infosupport marked this conversation as resolved.
Show resolved Hide resolved

Execute the initial test run only without doing actual mutation testing. Doing a dry run can be used to test that StrykerJS can run your test setup, for example, in CI pipelines.
florisg-infosupport marked this conversation as resolved.
Show resolved Hide resolved

### `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": {}
},
"dryRun": {
"description": "Runs only the initial test run, without running the mutators. This can be used to test for a correct setup of Stryker.",
florisg-infosupport marked this conversation as resolved.
Show resolved Hide resolved
"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.dryRun) {
this.log.info('Note: A dry-run has been started, no mutations will be run.');
}

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.dryRun) {
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(
'--dryRun',
'Execute the initial test run only without doing actual mutation testing. Doing a dry run 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}',
dryRun: false,
dryRunTimeoutMinutes: 5,
eventReporter: {
baseDir: 'reports/mutation/events',
Expand Down
14 changes: 14 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,18 @@ describe(MutationTestExecutor.name, () => {
// Assert
expect(testInjector.logger.info).calledWithExactly('Done in %s.', '2 seconds, tops!');
});

it('should short circuit when dryRun is enabled', async () => {
// Arrange
testInjector.options.dryRun = true;

// 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 }],
[['--dryRun'], { dryRun: 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