-
Notifications
You must be signed in to change notification settings - Fork 250
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
fix(JestTestRunner): run jest with --findRelatedTests #1235
Changes from 6 commits
202f7d8
eb97511
d8a0f6c
604ce6e
87bb365
8e64e42
bff462e
1d9e7f6
1de852f
6070dd7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,13 @@ | ||
import { getLogger } from 'stryker-api/logging'; | ||
import { RunnerOptions, RunResult, TestRunner, RunStatus, TestResult, TestStatus } from 'stryker-api/test_runner'; | ||
import { RunnerOptions, RunResult, TestRunner, RunStatus, TestResult, TestStatus, RunOptions } from 'stryker-api/test_runner'; | ||
import * as jest from 'jest'; | ||
import JestTestAdapterFactory from './jestTestAdapters/JestTestAdapterFactory'; | ||
|
||
export default class JestTestRunner implements TestRunner { | ||
private readonly log = getLogger(JestTestRunner.name); | ||
private readonly jestConfig: jest.Configuration; | ||
private readonly processEnvRef: NodeJS.ProcessEnv; | ||
private readonly enableFindRelatedTests: boolean; | ||
|
||
public constructor(options: RunnerOptions, processEnvRef?: NodeJS.ProcessEnv) { | ||
// Make sure process can be mocked by tests by passing it in the constructor | ||
|
@@ -15,19 +16,25 @@ export default class JestTestRunner implements TestRunner { | |
// Get jest configuration from stryker options and assign it to jestConfig | ||
this.jestConfig = options.strykerOptions.jest.config; | ||
|
||
// Get enableFindRelatedTests from stryker jest options or default to true | ||
this.enableFindRelatedTests = options.strykerOptions.jest.enableFindRelatedTests; | ||
if (this.enableFindRelatedTests === undefined) { | ||
this.enableFindRelatedTests = true; | ||
} | ||
|
||
// basePath will be used in future releases of Stryker as a way to define the project root | ||
// Default to process.cwd when basePath is not set for now, should be removed when issue is solved | ||
// https://github.com/stryker-mutator/stryker/issues/650 | ||
this.jestConfig.rootDir = options.strykerOptions.basePath || process.cwd(); | ||
this.log.debug(`Project root is ${this.jestConfig.rootDir}`); | ||
} | ||
|
||
public async run(): Promise<RunResult> { | ||
public async run(options?: RunOptions): Promise<RunResult> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I initially did that because tests started failing and I was unsure whether or not running without There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this is great. We have |
||
this.setNodeEnv(); | ||
|
||
const jestTestRunner = JestTestAdapterFactory.getJestTestAdapter(); | ||
|
||
const { results } = await jestTestRunner.run(this.jestConfig, process.cwd()); | ||
const { results } = await jestTestRunner.run(this.jestConfig, process.cwd(), this.enableFindRelatedTests, options && options.mutatedFileName); | ||
|
||
// Get the non-empty errorMessages from the jest RunResult, it's safe to cast to Array<string> here because we filter the empty error messages | ||
const errorMessages = results.testResults.map((testSuite: jest.TestResult) => testSuite.failureMessage).filter(errorMessage => (errorMessage)) as string[]; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,12 +5,16 @@ import { Configuration, runCLI, RunResult } from 'jest'; | |
export default class JestPromiseTestAdapter implements JestTestAdapter { | ||
private readonly log = getLogger(JestPromiseTestAdapter.name); | ||
|
||
public run(jestConfig: Configuration, projectRoot: string): Promise<RunResult> { | ||
public run(jestConfig: Configuration, projectRoot: string, enableFindRelatedTests: boolean, mutatedFileName?: string): Promise<RunResult> { | ||
jestConfig.reporters = []; | ||
const config = JSON.stringify(jestConfig); | ||
this.log.trace(`Invoking Jest with config ${config}`); | ||
if (enableFindRelatedTests && mutatedFileName) { | ||
this.log.trace(`Only running tests related to ${mutatedFileName}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this log message. |
||
} | ||
|
||
return runCLI({ | ||
...(enableFindRelatedTests && mutatedFileName && { _: [mutatedFileName], findRelatedTests: true}), | ||
config, | ||
runInBand: true, | ||
silent: true | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import { RunResult } from 'jest'; | ||
|
||
export default interface JestTestAdapter { | ||
run(config: object, projectRoot: string): Promise<RunResult>; | ||
run(config: object, projectRoot: string, enableFindRelatedTests: boolean, mutatedFileName?: string): Promise<RunResult>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we leave the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I understand. Do you mean to only pass the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yeah that is what I mean. The |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,8 +44,8 @@ export default class Sandbox { | |
return sandbox.initialize().then(() => sandbox); | ||
} | ||
|
||
public run(timeout: number, testHooks: string | undefined): Promise<RunResult> { | ||
return this.testRunner.run({ timeout, testHooks }); | ||
public run(timeout: number, testHooks: string | undefined, mutant?: TestableMutant): Promise<RunResult> { | ||
return this.testRunner.run({ timeout, testHooks, ...(mutant && { mutatedFileName: this.fileMap[mutant.fileName]}) }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we move the locating of the mutated file to the |
||
} | ||
|
||
public dispose(): Promise<void> { | ||
|
@@ -58,7 +58,7 @@ export default class Sandbox { | |
this.log.warn(`Failed find coverage data for this mutant, running all tests. This might have an impact on performance: ${transpiledMutant.mutant.toString()}`); | ||
} | ||
await Promise.all(mutantFiles.map(mutatedFile => this.writeFileInSandbox(mutatedFile))); | ||
const runResult = await this.run(this.calculateTimeout(transpiledMutant.mutant), this.getFilterTestsHooks(transpiledMutant.mutant)); | ||
const runResult = await this.run(this.calculateTimeout(transpiledMutant.mutant), this.getFilterTestsHooks(transpiledMutant.mutant), transpiledMutant.mutant); | ||
await this.reset(mutantFiles); | ||
return runResult; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can log on debug what we are doing with this setting?