testRegex 掩码选择错误的文件来运行测试

yao*_*bin 3 configuration reactjs jestjs

2018年7月13日更新:

经过一番折腾后,我明白了为什么testRegex不起作用。请参阅下面发布的我自己的答案。


原问题:

我正在为我的 React.js 项目编写测试代码。我正在使用react-scriptsand enzyme(我相信这jest也意味着)来运行和管理测试。这是package.json文件:

{
  "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?$"
  }
}
Run Code Online (Sandbox Code Playgroud)

之后npm install,我检查了版本:

  • 反应脚本@0.9.5
  • 酶@3.3.0
  • 笑话@18.1.0

(是的,我知道我正在使用旧版本的 React.js,但这就是我现在无法更改的,因为它不是我的个人项目。)

我不明白的testRegexofjest没有按我的预期工作。目前,我将所有测试文件放在__tests__文件夹下,并将它们命名为“something.test.js”。但是,如果您查看testRegex上面的内容,首先,它不会查找__tests__butabc作为文件夹名称,其次,它不会查找testbutdefg作为文件名。

由于上面的配置,我预计我的测试文件根本不会被执行。但是,当我运行时npm test,测试文件仍然被执行。

我做错了什么?

我的一些想法:

  • jest@18.1.0可能不支持testRegex
  • 我可能需要配置jestvia react-scripts,但它的用户指南似乎表明我可以按照我正在做的方式配置 jest(在 package.json 中放置“jest”部分)。
  • 我也尝试使用最新的jestv23.3,但仍然没有达到我的预期。
  • 我知道testMatch,但文档说“请注意,您不能指定两个选项”,所以我假设如果我testRegex在 中指定package.jsontestMatch则被忽略。这是真的?

yao*_*bin 5

经过一番黑客攻击后,我意识到这是因为如果您使用(注意它是标签的链接)在旧版本或最新版本中运行测试,testRegex则无法被覆盖(当我发布此答案时,最新版本是)。react-scriptsv0.9.5react-scripts1.1.4

以下是更多详细信息。

在上面我原来的问题中,我使用的是react-scripts v0.9.5. 当我运行CI=true npm test测试时,它react-scripts/scripts/test.js实际上已经运行了。这是一个包装脚本,最终仍然调用jest. 在这一行jest中,它创建 Jest 配置并作为其--config选项传递:

argv.push('--config', JSON.stringify(createJestConfig(
  relativePath => path.resolve(__dirname, '..', relativePath),
  path.resolve(paths.appSrc, '..'),
  false
)));
Run Code Online (Sandbox Code Playgroud)

跟踪此文件createJestConfig中的函数,您将看到它创建了一些 Jest 配置项并将它们作为 JavaScript 对象返回。

因此,jest(我正在使用) 最终使用具有字符串化 JSON 字符串的选项18.1.0运行。--config

如果你追踪下去jest.run,最终会看到这个runCli函数(这是一个链接),它读取这里的v18.1.0配置,并且这个函数是module导入的。readConfigjest-config

然后我们看一下jest-config模块。上述内容在此文件readConfig中定义。

readConfig函数调用,然后包含通过调用readRawConfig设置的配置:argvsetFromArgv

const readConfig = (argv: any, packageRoot: string) =>
  readRawConfig(argv, packageRoot)
    .then(config => Object.freeze(setFromArgv(config, argv)));
Run Code Online (Sandbox Code Playgroud)

以下是readRawConfig我对这些行的作用的评论(前面带有“ywen”)的实现:

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)
  });
};
Run Code Online (Sandbox Code Playgroud)

setFromArgv配置会覆盖 argv 上提供的配置,但不是testRegex其中之一。

如果您在命令行上提供自己的(--config例如 )CI=true npm test -- --config ./jest.config.js /path/to/your/test/file.js,则会在传递给 jest 的传递--config中添加两项:一项由您提供,另一项由react-scripts(秘密)创建。它们被分组为以下列表:argvcreateJestConfigargv.config

  config: 
   [ './jest.config.js',
     '{"collectCoverageFrom":["src/**/*.{js,jsx}"],...'
   ],
Run Code Online (Sandbox Code Playgroud)

当 被parseConfig调用时readRawConfigif (argv.config && typeof argv.config === 'string') {测试失败,因为传入的值是列表,而不是字符串。结果,parseConfig按原样返回此列表。然后将该列表存储在rawConfig. 的类型rawConfig仍然是object. 但在该行中const config = Object.assign({}, rawConfig);,它被转换成如下形式:

{ '0': './jest.config.js',
  '1': '{"collectCoverageFrom":["src/**/*.{js,jsx}"], ...
}'
Run Code Online (Sandbox Code Playgroud)

最终会在这一行失败,因为0or1不是有效的 Jest 配置。

导致在使用时react-scripts v0.9.5,其test脚本不支持自定义testRegex

react-scripts v1.1.4截至撰写本文时最新版本仍然如此。:它createJestConfig.js允许覆盖某些键,但testRegex仍然不是其中之一。