如何使用webpack玩笑?

时间:2015-03-05 04:54:51

标签: reactjs webpack jestjs

我使用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时,出现以下错误:

  

SyntaxError:/Users/mishamoroshko/react-component/src/tests/MyComponent.js:/Users/mishamoroshko/react-component/src/MyComponent.js:/ Users / mishamoroshko / react-component / src / MyComponent。 less:意外的令牌ILLEGAL

看起来webpack需要在jest运行测试之前处理require('./MyComponent.less')

我想知道是否需要使用像jest-webpack这样的东西。如果是,是否有办法指定多个scriptPreprocessor? (请注意,我已使用babel-jest

12 个答案:

答案 0 :(得分:24)

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

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

将moduleNameMapper键添加到packages.json配置中。项的键应该是所需字符串的正则表达式。使用&#39; .less&#39;的示例文件:

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

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

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

注释很重要,因为moduleNameMapper使用EmptyModule作为此模块的别名(read more about providesModule)。

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

如果您将moduleFileExtensions配置与&#39; js&#39;文件,然后确保您还将EmptyModule添加到&#39; unmockedModulePathPatterns&#39;。

这是我最终的最佳配置:

"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"
  ]
}

答案 1 :(得分:19)

我最终得到了以下黑客攻击:

// 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, '');
  }
};

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

答案 2 :(得分:9)

我发现使用Jest moduleNameMapper配置它更简单。

&#13;
&#13;
// package.json

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

// style-mock.js

module.exports = {};
&#13;
&#13;
&#13;

Jest&#39; tutorial page的详细信息。

答案 3 :(得分:4)

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

答案 4 :(得分:3)

来自Jest docs

// in terminal, add new dependency: identity-obj-proxy
npm install --save-dev identity-obj-proxy

// package.json (for CSS Modules)
{
  "jest": {
    "moduleNameMapper": {
      "\\.(css|less)$": "identity-obj-proxy"
    }
  }
}

上面的代码段会将所有.less个文件路由到新的依赖项identity-obj-proxy,这将在调用时返回带有类名的字符串,例如'styleName'的{​​{1}}。

答案 5 :(得分:2)

我认为一个不太常见的解决方案是将预处理器包装在与javascript文件匹配的文件名的条件下:

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

即使您没有在需求行中明确设置扩展名并且不需要在源代码上进行正则表达式替换,这也有效。

答案 6 :(得分:1)

我遇到过类似问题

import React, { PropTypes, Component } from 'react';
import styles from './ContactPage.css';
import withStyles from '../../decorators/withStyles';

@withStyles(styles)
class ContactPage extends Component {

参见https://github.com/kriasoft/react-starter-kit/blob/9204f2661ebee15dcb0b2feed4ae1d2137a8d213/src/components/ContactPage/ContactPage.js#L4-L7

的示例

为了运行Jest,我有两个问题:

  • 导入.css
  • 应用装饰器@withStylesTypeError: <...> (0 , _appDecoratorsWithStyles2.default)(...) is not a function

第一个是通过在脚本预处理器中模拟.css本身来解决的。

第二个是通过使用unmockedModulePathPatterns

从自动锁定中排除装饰器来解决的
module.exports = {
  process: function (src, filename) {

    ...

    if (filename.match(/\.css$/)) src = '';

    ...

    babel.transform(src, ...
  }
}

基于https://github.com/babel/babel-jest/blob/77a24a71ae2291af64f51a237b2a9146fa38b136/index.js

的示例

另请注意:使用jest预处理器时,应清除缓存:

$ rm node_modules/jest-cli/.haste_cache -r

答案 7 :(得分:0)

从Misha的回应中汲取灵感,我创建了一个NPM包来解决这个问题,同时还处理了我遇到的一些场景:

webpack-babel-jest

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

答案 8 :(得分:0)

如果你正在使用babel,你可以使用https://github.com/Shyp/babel-plugin-import-noop之类的东西在babel变换期间删除不需要的导入,并配置你的.babelrc test env来使用插件,如下所示: / p>

{
  "env": {
    "development": {
      ...
    },
    "test": {
      "presets": [ ... ],
      "plugins": [
        ["import-noop", {
          "extensions": ["scss", "css"]
        }]
      ]
    }
  }
}

答案 9 :(得分:0)

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

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

答案 10 :(得分:0)

我们遇到了与CSS文件类似的问题。如前所述jest-webpack解决了这个问题。您也不必模拟或使用任何模块映射器。对于我们来说,我们将{npm测试命令从jest替换为jest-webpack,它只是起作用。

答案 11 :(得分:0)

问了这个问题已有5年了,但对我来说仍然很困惑,我不敢相信它如此难于开玩笑和webpack起作用,直到我尝试了这一点:

添加babel-jest和babel预设:

yarn add --dev babel-jest @babel/preset-env

添加babel配置:

// babel.config.js
module.exports = {
  presets: ["@babel/preset-env"]
};

这可能对您不起作用,因为问题标题仅涉及jest和webpack,人们可能像我一样偶然发现这篇文章,这对于如何使webpack成为jest毫无用处,我希望至少我的回答对您有所帮助他们,如果这对您没有帮助。