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

Keep ARGV only in CLI files #4012

Merged
merged 1 commit into from
Jul 14, 2017

Conversation

aaronabramov
Copy link
Contributor

right now we're passing both ARGV and globalConfig all the way down to test runner. Also we mutate both of them as we pass it down (globalConfig is frozen, but we clone it instead of directly mutating).

This PR separates ARGV from globalObject and makes it that ARGV is only used in CLI context (ARGV only represents the actual passed arguments to CLI now).

globalObject is still mutable (frozen, but rewritten) and i believe Jest workflow suggests that it should be this way. For example, when we run --watch mode, user's interactions change globalConfig and then we re-run Jest with the new config.

cc @rogeliog for watch stuff

Copy link
Contributor Author

@aaronabramov aaronabramov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it also greatly simplifies the argument flow of jest.
we don't need to pass testPathPattern, testNamePattern and testPattern as a string throughout the flow.
and we don't need TestSelectionConfig any more, since it was a derived data structure

@@ -97,7 +77,7 @@ exports[`Custom Reporters Integration default reporters enabled 2`] = `
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: <<REPLACED>>
Ran all test suites matching \\"add.test.js\\".
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed in #4006 this now prints the pattern instead of mix of pattern+raw input

@@ -4,7 +4,7 @@ exports[`Watch mode flows Runs Jest once by default and shows usage 1`] = `
Array [
"
Watch Usage
› Press o to only run tests related to changed files.
› Press a to run all tests.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not the actual behavior change, rather the test change because of different default mock value

@@ -228,5 +228,3 @@ exports[`Watch mode flows Results in pattern mode get truncated appropriately 2`
[MOCK - cursorTo(12, 5)]
[MOCK - cursorRestorePosition]"
`;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i used a direct comparison here instead of snapshot

@@ -1,73 +0,0 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need this data structure any more, since all needed data can be taken from globalConfig now

updateArgv(argv, 'watchAll', {noSCM: true});
testSelectionConfig = getTestSelectionConfig(argv);
data = await source.getTestPaths(testSelectionConfig);
// updateArgv(argv, 'watchAll', {noSCM: true});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this line seems to be noop now, but i wasn't 100% sure, i'll follow up.
(we might be missing a test case that tests this behavior)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that I understand why this is not needed anymore

* @flow
*/

module.exports = (testPathPattern: string) => new RegExp(testPathPattern, 'i');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we serialize/deserialize patterns when we spawn workers, i chose to have a single function that can produce consistent result on both sides (probably should put it in a comment in this file)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this one

@@ -22,7 +21,8 @@ import isValidPath from './lib/is_valid_path';
import preRunMessage from './pre_run_message';
import createContext from './lib/create_context';
import runJest from './run_jest';
import updateArgv from './lib/update_argv';
// import updateArgv from './lib/update_argv';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: remove

noStackTrace: options.noStackTrace,
nonFlagArgs: options.nonFlagArgs,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the value of ARGV._ with a normal name

logHeapUsage: options.logHeapUsage,
mapCoverage: options.mapCoverage,
maxWorkers: options.maxWorkers,
noSCM: undefined,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one is complicated, because we only know its value after we searched for tests (jest-changed-files).
currently in Jest master we modify globalConfig after we get the result and i think this is not a good pattern.
I think we should split runJest function into two and run them sequentially:

const globalConfig = readConfig(...);
const {noSCM, tests} = findTests(globalConfig);
globalConfig.noSCM = noSCM;
globalConfig.somethingElse = ... // there's a few modifications that we're already doing in runJest

Object.freeze(globalConfig); // at this point config is immutable. no hacks
runJest(globalConfig);

newOptions.nonFlagArgs = argv._;
newOptions.testPathPattern = buildTestPathPattern(argv);
newOptions.json = argv.json;
newOptions.lastCommit = argv.lastCommit;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure if it's the right way to do it. Adding these values to the switch block above leaves them undefined

@cpojer
Copy link
Member

cpojer commented Jul 12, 2017

I don't think I agree that this many new options have to be added to GlobalConfig. To keep this manageable, given that they all mostly belong to one or two features, I'd recommend grouping them in one or two objects within GlobalConfig instead. What do you think?

@aaronabramov
Copy link
Contributor Author

@cpojer i don't think we should go this way honestly.
i don't see how flat object is less manageable than hierarchical structure.
most of our config options used only for one/two features (expand, logHeapUsage, notify, bail, etc...)
i definitely though about grouping all new options first, but then realized that this only makes things more complicated. (have to deepFreeze, no one to one mapping with CLI, have to look into object structure every time because you don't know which group it belongs to, flowtype refining magic, etc.)

if we do want to move to grouped configs, a can see it as

globalConfig: {
  testSelection: {testPathPattern: ..., testNamePattern: ..., ...},
  runnerOptions: {onlyChanged: ..., bail: ..., maxWorkers: ...},
  coverage: {threshold: ..., coverageIgnorePatterns: ...},
  // ...
}

but then you have to decide whether --coverage will be a part of runnerOptions or coverage group. or if updateSnapshot should be a runner options or have its own snapshot group, and if it's its own group.

so basically my thoughts are - if we start grouping options together, there's no good convention or rule of how to group them and it will eventually become very confusing :(

@codecov-io
Copy link

codecov-io commented Jul 12, 2017

Codecov Report

Merging #4012 into master will increase coverage by 0.07%.
The diff coverage is 54.54%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #4012      +/-   ##
==========================================
+ Coverage   60.31%   60.39%   +0.07%     
==========================================
  Files         196      196              
  Lines        6761     6754       -7     
  Branches        6        6              
==========================================
+ Hits         4078     4079       +1     
+ Misses       2680     2672       -8     
  Partials        3        3
Impacted Files Coverage Δ
packages/jest-config/src/validate_pattern.js 100% <ø> (ø)
packages/jest-config/src/valid_config.js 100% <ø> (ø) ⬆️
packages/jest-config/src/index.js 0% <ø> (ø) ⬆️
packages/jest-cli/src/search_source.js 75% <0%> (-1.28%) ⬇️
...ckages/jest-cli/src/reporters/coverage_reporter.js 49.36% <0%> (-0.64%) ⬇️
...ackages/jest-cli/src/reporters/summary_reporter.js 21.31% <0%> (-1.27%) ⬇️
packages/jest-cli/src/run_jest.js 0% <0%> (ø) ⬆️
packages/jest-cli/src/reporters/notify_reporter.js 12.5% <0%> (-0.55%) ⬇️
packages/jest-cli/src/get_changed_files_promise.js 100% <100%> (ø) ⬆️
...ckages/jest-cli/src/test_path_pattern_to_regexp.js 100% <100%> (ø)
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 03c6814...942dde3. Read the comment docs.

\\"path\\": false
},
\\"options\\": {
\\"Dmitrii Abramov\\": \\"Awesome\\"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably needs to be updated too :D

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spare that for another PR :p

globalConfig,
mode,
options,
}: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not so many options here, so maybe we can switch to function arguments instead of destructuring? We could avoid duplicating the names in type def.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was just arguments before, but there's a lot of calls with either mode or options undefined, so it became
updateGlobalConfig(globalConfig, null, options)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually you're right, i don't see any reason to keep it two separate arguments. i'll just merge them into

updateGlobalConfig(globalConfig: GlobalConfig, options: Options);

@@ -263,7 +263,6 @@ const _run = async (

argv.watch || argv.watchAll
Copy link
Collaborator

@thymikee thymikee Jul 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be taken from globalConfig now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh wow... i didn't notice this. This simplifies things even further. All of those functions don't need argv any more. (and flow didn't catch that again) :)

updateArgv(argv, argv.watch ? 'watch' : 'watchAll', {
testNamePattern: argv.testNamePattern,
testPathPattern: argv.testPathPattern || (argv._ || []).join('|'),
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of lack of this update logic, globalConfig.onlyChanged is not updated properly on the first run, resulting in tests being run, despite there's nothing changed in git.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! adding it back (although updating onlyChanged implicitly seems like something we should fix in the future)

Copy link
Collaborator

@thymikee thymikee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the bug with watch mode I mentioned in comments and I think this is good to go. Looks good to me for now.

@cpojer
Copy link
Member

cpojer commented Jul 13, 2017

I'd like it if we could keep "testSelection" as a globalConfig param.

Just to double check, these args are not part of InitialOptions, therefore cannot be specified in a configuration file, right? I think that's the right way to go for these, there is never a time when hardcoding the test selection makes sense imho.

@aaronabramov
Copy link
Contributor Author

aaronabramov commented Jul 13, 2017 via email

@cpojer
Copy link
Member

cpojer commented Jul 13, 2017

Ok, you convinced me. No mutations, though, only copying!

@aaronabramov
Copy link
Contributor Author

aaronabramov commented Jul 13, 2017 via email

Copy link
Contributor

@rogeliog rogeliog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice clean up, watch mode looks good to me... Just some really minor comments

@@ -22,10 +22,11 @@ jest.doMock(
() =>
function() {
const args = Array.from(arguments);
const {onComplete} = args[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nit: couldn't this be const [onComplete] = args?

options?: Options,
}): GlobalConfig => {
// $FlowFixMe Object.assign
const newConfig: GlobalConfig = Object.assign({}, globalConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, we are not mutating it any more!

updateArgv(argv, 'watchAll', {noSCM: true});
testSelectionConfig = getTestSelectionConfig(argv);
data = await source.getTestPaths(testSelectionConfig);
// updateArgv(argv, 'watchAll', {noSCM: true});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that I understand why this is not needed anymore

* @flow
*/

module.exports = (testPathPattern: string) => new RegExp(testPathPattern, 'i');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this one

@aaronabramov
Copy link
Contributor Author

ok. seems like i addressed them all!

@aaronabramov aaronabramov merged commit 7bf328d into jestjs:master Jul 14, 2017
@aaronabramov aaronabramov deleted the test_path_pattern branch July 14, 2017 00:40
tushardhole pushed a commit to tushardhole/jest that referenced this pull request Aug 21, 2017
@github-actions
Copy link

This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 13, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants