-
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
fix(JestTestRunner): run jest with --findRelatedTests #1235
Conversation
Pass sandbox fileName to the test runner.
@RobertBroersma in |
2c456da
to
604ce6e
Compare
@kmdrGroch You are right! I had some trouble running tests and checks locally, but I think I got it now. Will push some fixes soon. |
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.
Awesome to see you found you're way around our repository. I've already taken a look and it looks good. I've got 2 suggestions already.
packages/stryker-jest-runner/src/jestTestAdapters/JestPromiseTestAdapter.ts
Outdated
Show resolved
Hide resolved
Also add to Sandbox test
@nicojs Thanks for the feedback! I've processed your comments and expanded the test for Should we consider adding a configuration option for running with or without |
Can you explain to me how the filtering works? If I have a fooTest.js file that tests foo.js, but I have high doubts that it would work in 100% of the cases, because of the dynamic nature of JavaScript. |
I've never questioned the working of it tbh, but I've went and looked it up. From a curious stackoverflow user: https://stackoverflow.com/questions/44066996/how-does-jest-findrelatedtests-work-under-the-hood
However there have been reports of it not working optimally, which have been recognized by the Jest team, e.g. jestjs/jest#6062 |
Thanks for figuring this out @RobertBroersma. With all side effects in mind, let's make it configurable. Would you mind making the change? The default can be |
No problem! I agree making it configurable would be good. I'll make the change. |
@nicojs I've made the flag configurable. Not sure if this is the best way or if and how I should add any tests for it. Let me know what you think! |
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.
Great, this PR is looking better and better. I've got some small remarks about naming and functionality location.
We should indeed add some tests in "JestPromiseTestAdapterSpec.ts" to see if the correct options are provided. Are you willing to add those as well?
We also shouldn't forget to document this feature in the readme.
@@ -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; |
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?
packages/stryker/src/Sandbox.ts
Outdated
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Could we move the locating of the mutated file to the runMutant
call? It is specific to the case of running when targeting a mutant. I feel like the separation of concerns is intermingled now.
packages/stryker-jest-runner/test/unit/jestTestAdapters/JestPromiseTestAdapterSpec.ts
Show resolved
Hide resolved
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
Could we leave the name mutatedFileName
out of this interface. It is not a clean separation of concerns. The JestTestAdapter shouldn't care about mutants, only about running tests. I think these 2 options can be combined into 1: fileNameUnderTest
or something. If it is provided, it can add {findRelatedTests: true, _: [fileNameUnderTest]
.
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.
I'm not sure I understand. Do you mean to only pass the fileNameUnderTest
when running related to a specific file? I.e. when the flag is true and we're testing a mutant?
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.
I.e. when the flag is true and we're testing a mutant?
Yeah that is what I mean. The JestTestAdapter
should be an adapter for jest. No more, no less. It shouldn't make decisions.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
I like this log message.
I'll be working on your feedback hopefully soon. Got a bit busy at work the past days! |
@RobertBroersma just let us know if you need some more help. |
@nicojs I'm hoping to find some time this evening. I'll let you know if I run into any issues. |
@nicojs I've processed your feedback. I think I understood most of it, let me know what you think! I've added some unit tests. Was thinking about some integration tests, but couldn't quite figure them out yet. You think we should add some? |
// 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 comment
The reason will be displayed to describe this comment to others. Learn more.
options
here don't need a ?
. It is always filled. No need for null/undefined checks.
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.
I think I initially did that because tests started failing and I was unsure whether or not running without RunOptions
was a case. I've taken a look at the other *TestRunnerSpec
s and I've added some RunOptions
to the Jest ones. Is this correct?
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.
Yeah, this is great. We have RunnerOptions
as options when creating a runner and RunOptions
as options when calling the run()
method. Confusing, I know 🙈
@@ -37,6 +38,18 @@ describe('JestPromiseTestAdapter', () => { | |||
}, [projectRoot])); | |||
}); | |||
|
|||
it('should call the runCLI method with the --findRelatedTests flag', async () => { |
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.
Great test!
Thanks for the quick response! I first want to merge #1260. In there we have an integration test that tests the score of an actual stryker run with the jest runner. After that, I'll merge master in this branch and see if it works locally as expected (also will keep an eye on performance to see it improved). After that, I'll merge. Should still be today. Awesome job 👍 |
Worked great, although no performance improvement for the integration test (takes 1 minute and 1 second for both cases locally on my machine). Will merge when green 👍 |
Thanks @nicojs ! |
Pass sandbox fileName to the test runner.
It's probably not the best code, but it works. It speeds up my stryker runs from around 2h45m to around 45m (70% faster!).
It would be great if someone could assist me in writing tests and giving me some pointers for cleaning up/refactoring my code, as the project is quite a lot to take in for me atm.
Cheers, let me know what you think!
PS. As I'm not entirely clear on how to run the project locally on my own code, I had to replace
importModule(name);
withimportModule(__dirname + '../../../' + name);
inPluginLoader.ts
in order for stryker to be able to find its plugins. Not sure why.Fixes #1226