如何在Webpack中使用Jest?

我使用webpack开发一个React组件。这是它的简单版本:

'use strict';

require('./MyComponent.less');

var React = require('react');

var MyComponent = React.createClass({
  render() {
    return (
      <div className="my-component">
        Hello World
      </div>
    );
  }
});

module.exports = MyComponent;

现在,我想使用jest测试此组件这是我的相关内容package.json

"scripts": {
  "test": "jest"
},
"jest": {
  "rootDir": ".",
  "testDirectoryName": "tests",
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "unmockedModulePathPatterns": [
    "react"
  ]
}

运行时npm test,出现以下错误:

语法错误:/Users/mishamoroshko/react-component/src/tests/MyComponent.js:/Users/mishamoroshko/react-component/src/MyComponent.js:/Users/mishamoroshko/react-component/src/MyComponent.less:意外代币非法

看起来webpack需要先处理require('./MyComponent.less')才能开玩笑才能运行测试。

我想知道是否需要使用诸如jest-webpack之的东西如果是,是否可以指定多个scriptPreprocessors?(请注意,我已经使用了babel-jest

达蒙2020/03/24 10:00:47

CSS文件也有类似的问题。正如您之前提到的jest-webpack可以很好地解决此问题。您也不必模拟或使用任何模块映射器。对我们来说,我们从我们的替代NPM测试命令jestjest-webpack,它只是工作。

小胖Davaid2020/03/24 10:00:47

我最终遇到了以下黑客:

// package.json

"jest": {
  "scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
  ...
}


// jest-script-preprocessor.js
var babelJest = require("babel-jest");

module.exports = {
  process: function(src, filename) {
    return babelJest.process(src, filename)
      .replace(/^require.*\.less.*;$/gm, '');
  }
};

但是,我仍然想知道该问题的正确解决方案是什么。

古一番长小小2020/03/24 10:00:47

如果您使用的是babel,则可以在https://github.com/Shyp/babel-plugin-import-noop之类的东西进行babel转换期间剥离不需要的导入,并配置.babelrc testenv以使用该插件,如下所示:

{
  "env": {
    "development": {
      ...
    },
    "test": {
      "presets": [ ... ],
      "plugins": [
        ["import-noop", {
          "extensions": ["scss", "css"]
        }]
      ]
    }
  }
}
2020/03/24 10:00:47

我认为,一种不太hacky的解决方案是将预处理器包装在与JavaScript文件匹配的文件名中:

if (filename.match(/\.jsx?$/)) {
    return babelJest.process(src, filename);
} else {
    return '';
}

即使您没有在require行中显式设置扩展名,也不需要源代码上的正则表达式替换,此方法仍然有效。

村村2020/03/24 10:00:47

Webpack是一个很棒的工具,但是我不需要使用Jest单元测试来测试它的行为,在运行单元测试之前添加Webpack构建只会减慢该过程。教科书的答案是使用"moduleNameMapper"选项模拟非代码依赖

https://facebook.github.io/jest/docs/webpack.html#handling-static-assets

JinJin2020/03/24 10:00:47

从Misha的响应中获得启发,我创建了一个NPM程序包来解决此问题,同时还处理了一些我遇到的方案:

webpack-babel-jest

希望这可以节省下一个人几个小时。

宝儿2020/03/24 10:00:46

我最近发布了Jestpack,这可能会有所帮助。它首先使用Webpack构建您的测试文件,因此任何自定义模块解析度/加载器/插件等都可以正常工作,并且最终使用JavaScript。然后,它为Jest提供了一个定制的模块加载器,它了解Webpack模块的运行时。

2020/03/24 10:00:46

我只是发现Jest的moduleNameMapper配置更加简单

// package.json

"jest": {
    "moduleNameMapper": {
      "^.+\\.scss$": "<rootDir>/scripts/mocks/style-mock.js"
    }
}

// style-mock.js

module.exports = {};

在Jest的教程页面上有更多详细信息

小胖2020/03/24 10:00:46

我发现忽略必需模块的最干净的解决方案是使用moduleNameMapper配置(适用于最新版本0.9.2)

该文档很难遵循。希望以下内容对您有所帮助。

将moduleNameMapper密钥添加到您的packages.json配置中。项目的键应为所需字符串的正则表达式。“ .less”文件的示例:

"moduleNameMapper": { "^.*[.](less|LESS)$": "EmptyModule" },

将EmptyModule.js添加到您的根文件夹中:

/**
 * @providesModule EmptyModule
 */
module.exports = '';

该注释很重要,因为moduleNameMapper使用EmptyModule作为此模块的别名(有关更多信息,请参见ProvidesModule )。

现在,每个与正则表达式匹配的require引用都将替换为空字符串。

如果将moduleFileExtensions配置与“ js”文件一起使用,请确保还将EmptyModule也添加到“ unmockedModulePathPatterns”中。

这是我最后的玩笑配置:

"jest": {
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "moduleFileExtensions": ["js", "json","jsx" ],
  "moduleNameMapper": {
    "^.*[.](jpg|JPG|gif|GIF|png|PNG|less|LESS|css|CSS)$": "EmptyModule"
  },
  "preprocessorIgnorePatterns": [ "/node_modules/" ],
  "unmockedModulePathPatterns": [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils",
    "<rootDir>/EmptyModule.js"
  ]
}