Update on 2018/07/13:
After hacking around, I figured out why the testRegex didn't work. See my own answer posted below.
Original Question:
I am writing the test code for my React.js project. I'm using react-scripts and enzyme (which I believe implies jest as well) to run and manage the tests. Here is the package.json file:
{
"name": "front",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "~15.5.4",
"react-dom": "~15.5.4",
"react-scripts": "0.9.5",
"redux": "~3.6.0",
"react-redux": "~5.0.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"enzyme": "^3.3.0",
"enzyme-adapter-react-15": "^1.0.6",
"react-test-renderer": "~15.5.4"
},
"jest": {
"testRegex": "(/abc/.*|(\\.|/)(defg|spec))\\.jsx?$"
}
}
After npm install, I checked the versions:
(Yeah, I know I'm using an older version of React.js but that's what I can't change right now because it is not my personal project.)
What I don't understand is the testRegex of jest doesn't work as I expect. Currently, I put all my test files under __tests__ folder and name them as "something.test.js". However, if you look at the testRegex above, firstly, it doesn't look for __tests__ but abc as the folder name and, secondly, it doesn't look for test but defg as the file name.
Because of the configuration above, I was expecting my test files wouldn't be executed at all. However, when I ran npm test, the test files were still executed.
What did I do wrong?
Some of my thoughts:
[email protected] may not support the testRegex.jest via react-scripts but its user guide seems to show that I can just configure jest the way I'm doing (putting a "jest" section in package.json).jest v23.3, but it still didn't work as I expected.testMatch, but the documentation says "note that you cannot specify both options", so I am assuming that if I have specified testRegex in package.json, testMatch is ignored. Is this true?After hacking around, I realized it is because testRegex cannot be overridden if you use react-scripts(note it is the link to the tag v0.9.5) to run the tests, in either the older or the latest versions (By the time I posted this answer, the latest version of react-scripts was 1.1.4).
Here are more details.
In my original question above, I was using react-scripts v0.9.5. When I ran CI=true npm test to run the test, it was react-scripts/scripts/test.js that was actually run. This is a wrapper script that eventually still calls jest. In this line, it creates Jest configuration and passes into jest as its --config options:
argv.push('--config', JSON.stringify(createJestConfig(
relativePath => path.resolve(__dirname, '..', relativePath),
path.resolve(paths.appSrc, '..'),
false
)));
Tracking down the createJestConfig function in this file, you'll see it creates some of the Jest configuration items and returns them as a JavaScript object.
Therefore, jest (I'm using 18.1.0) is eventually run with a --config option that has a stringified JSON string.
If you trace down jest.run, it eventually comes to this runCli function(this is a link to v18.1.0) which reads the configuration here, and this readConfig function is imported from jest-config module.
Then let's look at the jest-config module. The aforesaid readConfig is defined in this file.
The readConfig function calls readRawConfig and then includes the configurations set from argv by calling setFromArgv:
const readConfig = (argv: any, packageRoot: string) =>
readRawConfig(argv, packageRoot)
.then(config => Object.freeze(setFromArgv(config, argv)));
Here is the readRawConfig implementation with my comments (preceded with "ywen") about what the lines do:
const parseConfig = argv => {
if (argv.config && typeof argv.config === 'string') {
// If the passed in value looks like JSON, treat it as an object.
if (argv.config[0] === '{' && argv.config[argv.config.length - 1] === '}') {
return JSON.parse(argv.config);
}
}
return argv.config;
};
const readRawConfig = (argv, root) => {
// [ywen]
// Calls the `parseConfig` above. Remember that react-scripts's
// test.js passes in the configuration as a stringified JSON
// string, so the "If the passed in value looks like JSON..."
// test is met. The stringified JSON string is read and parsed
// back to a JavaScript object, returned, and stored in the
// rawConfig variable.
const rawConfig = parseConfig(argv);
if (typeof rawConfig === 'string') {
return loadFromFile(path.resolve(process.cwd(), rawConfig));
}
if (typeof rawConfig === 'object') {
// [ywen]
// Because `rawConfig` is a JS object, this if branch is
// executed. The function returns with the normalized
// configuration, so the `loadFromPackage` function, which
// reads the `jest` configuration from the `package.json`,
// is **NOT** called.
const config = Object.assign({}, rawConfig);
config.rootDir = config.rootDir || root;
return Promise.resolve(normalize(config, argv));
}
return loadFromPackage(path.join(root, 'package.json'), argv).
then(config => {
console.log('package.json config: ', config);
config || normalize({ rootDir: root }, argv)
});
};
The setFromArgv overrides the configuration with those provided on the argv, but testRegex is NOT one of them.
If you provide your own --config on the command line such as CI=true npm test -- --config ./jest.config.js /path/to/your/test/file.js, there will be two --config items added to the argv passed to jest: one is provided by you, the other is (secretly) created by react-scripts's createJestConfig. They are grouped as a list in argv.config:
config:
[ './jest.config.js',
'{"collectCoverageFrom":["src/**/*.{js,jsx}"],...'
],
When the parseConfig is called by readRawConfig, the if (argv.config && typeof argv.config === 'string') { test fails because the passed in value is a list, not a string. As a result, the parseConfig returns this list as-is. This list is then stored in rawConfig. The type of rawConfig is still object. But in the line const config = Object.assign({}, rawConfig);, it is transformed into something as follows:
{ '0': './jest.config.js',
'1': '{"collectCoverageFrom":["src/**/*.{js,jsx}"], ...
}'
which will finally fail at this line because 0 or 1 is not a valid Jest configuration.
As a result, when using react-scripts v0.9.5, its test script does not support the customization of testRegex.
This is still the case in react-scripts v1.1.4 which is the latest version by the time of this writing. The createJestConfig.js: it allows some of the keys to be overridden, but testRegex is still not one of them.
try this: create a separate file named jest.config.js
module.exports = {
coverageDirectory: "coverage",
moduleFileExtensions: [
"ts",
"tsx",
"js"
],
testEnvironment: "node",
testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With