Skip to content

Commit eb44060

Browse files
fix(cli): ensure that argument order is correct for Jest (#3827)
This ensures that CLI arguments are ordered correctly when we pass them to Jest. In particular, we want to ensure that all flags of the type `--maxWorkers=0` and the like are _before_ any flags which we don't know about, like `my-spec-file.ts` (the latter being actually a match pattern for which spec files to run). In other words, if the user passes arguments like this: ``` --e2e foo.spec.ts ``` or ``` --e2e -- foo.spec.ts ``` We need to ensure we use something like ``` ["--e2e", "foo.spec.ts"] ``` to generate the Jest config. The wrinkle is that after we've parsed our known CLI arguments (in the `cli` module) we do some addition modification of the arguments, based on values set in the `Config`, in the `buildJestArgv` function. In particular, we'll look to see if a `maxWorkers` flag is already passed and, if not, we add one to the args before they're used to build the Jest configuration. Before this change that would result in an array like this being passed to Jest: ``` ["--e2e", "foo.spec.ts", "--maxWorkers=0"] ``` because we simply stuck the new `--maxWorkers` arg right on the end of the already-combined array (combined because it's basically `knownArgs + unknownArgs`). No good! Why no good? Well, basically because Jest works best if the filename matches are at the end. It's behavior if they're _not_ is, unfortunately, inconsistent and it will work sometimes, but it (as far as I have tested it!) _always_ works if the pattern is at the end. So in order to provide a guarantee the pattern is at the end, we modify a copy of `knownArgs` with flags like this and then produce a new, combined array to pass to Jest when we're all done, so it looks like this instead: ``` ["--e2e", "--maxWorkers=0", "foo.spec.ts"] ``` Much better!
1 parent c786d8f commit eb44060

File tree

2 files changed

+42
-6
lines changed

2 files changed

+42
-6
lines changed

src/testing/jest/jest-config.ts

+17-5
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,27 @@ function getLegacyJestOptions(): Record<string, boolean | number | string> {
4646
export function buildJestArgv(config: d.ValidatedConfig): Config.Argv {
4747
const yargs = require('yargs');
4848

49-
const args = [...config.flags.knownArgs.slice(), ...config.flags.unknownArgs.slice()];
49+
const knownArgs = config.flags.knownArgs.slice();
5050

51-
if (!args.some((a) => a.startsWith('--max-workers') || a.startsWith('--maxWorkers'))) {
52-
args.push(`--max-workers=${config.maxConcurrentWorkers}`);
51+
if (!knownArgs.some((a) => a.startsWith('--max-workers') || a.startsWith('--maxWorkers'))) {
52+
knownArgs.push(`--max-workers=${config.maxConcurrentWorkers}`);
5353
}
5454

5555
if (config.flags.devtools) {
56-
args.push('--runInBand');
57-
}
56+
knownArgs.push('--runInBand');
57+
}
58+
59+
// we combine the modified args and the unknown args here and declare the
60+
// result read only, providing some typesystem-level assurance that we won't
61+
// mutate it after this point.
62+
//
63+
// We want that assurance because Jest likes to have any filepath match
64+
// patterns at the end of the args it receives. Those args are going to be
65+
// found in our `unknownArgs`, so while we want to do some stuff in this
66+
// function that adds to `knownArgs` we need a guarantee that all of the
67+
// `unknownArgs` are _after_ all the `knownArgs` in the array we end up
68+
// generating the Jest configuration from.
69+
const args: ReadonlyArray<string> = [...knownArgs, ...config.flags.unknownArgs];
5870

5971
config.logger.info(config.logger.magenta(`jest args: ${args.join(' ')}`));
6072

src/testing/jest/test/jest-config.spec.ts

+25-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ describe('jest-config', () => {
4242
expect(jestArgv.maxWorkers).toBe(2);
4343
});
4444

45-
it('forces --maxWorkers=4 arg when e2e test and --ci', () => {
45+
it('passes default --maxWorkers=0 arg when e2e test and --ci', () => {
4646
const args = ['test', '--ci', '--e2e'];
4747
const config = mockValidatedConfig();
4848
config.flags = parseFlags(args);
@@ -55,6 +55,20 @@ describe('jest-config', () => {
5555
expect(jestArgv.maxWorkers).toBe(0);
5656
});
5757

58+
it('passed default --maxWorkers=0 arg when e2e test and --ci with filepath', () => {
59+
const args = ['test', '--ci', '--e2e', '--', 'my-specfile.spec.ts'];
60+
const config = mockValidatedConfig();
61+
config.flags = parseFlags(args);
62+
63+
expect(config.flags.args).toEqual(['--ci', '--e2e', '--', 'my-specfile.spec.ts']);
64+
expect(config.flags.unknownArgs).toEqual(['--', 'my-specfile.spec.ts']);
65+
66+
const jestArgv = buildJestArgv(config);
67+
expect(jestArgv.ci).toBe(true);
68+
expect(jestArgv.maxWorkers).toBe(0);
69+
expect(jestArgv._).toEqual(['my-specfile.spec.ts']);
70+
});
71+
5872
it('pass --maxWorkers=2 arg to jest', () => {
5973
const args = ['test', '--maxWorkers=2'];
6074
const config = mockValidatedConfig();
@@ -200,5 +214,15 @@ describe('jest-config', () => {
200214

201215
const jestArgv = buildJestArgv(config);
202216
expect(jestArgv.json).toBe(true);
217+
// the `_` field holds any filename pattern matches
218+
expect(jestArgv._).toEqual(['my-component.spec.ts']);
219+
});
220+
221+
it('should parse multiple file patterns', () => {
222+
const args = ['test', '--spec', '--json', '--', 'foobar/*', 'my-spec.ts'];
223+
const jestArgv = buildJestArgv(mockValidatedConfig({ flags: parseFlags(args) }));
224+
expect(jestArgv.json).toBe(true);
225+
// the `_` field holds any filename pattern matches
226+
expect(jestArgv._).toEqual(['foobar/*', 'my-spec.ts']);
203227
});
204228
});

0 commit comments

Comments
 (0)