首页 文章

如何使用webpack玩笑?

提问于
浏览
46

我使用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

11 回答

  • 1

    我们在CSS文件中遇到了类似的问题 . 正如你之前提到的jest-webpack解决了这个问题 . 您也不必模拟或使用任何模块映射器 . 对于我们来说,我们将npm测试命令从 jest 替换为 jest-webpack ,它刚刚起作用 .

  • 0

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

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

  • 3

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

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

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

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

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

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

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

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

    如果您将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"
    ]
    }
    
  • 0

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

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

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

  • 19

    我刚发现它's even simpler with Jest' s moduleNameMapper 配置 .

    // package.json
    
    "jest": {
        "moduleNameMapper": {
          "^.+\\.scss$": "<rootDir>/scripts/mocks/style-mock.js"
        }
    }
    
    // style-mock.js
    
    module.exports = {};
    

    Jest的更多细节tutorial page .

  • 2

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

  • 20

    来自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' for styles.styleName .

  • 0

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

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

    即使您没有在require行中显式设置扩展名并且不需要在源上进行正则表达式替换,这也可以工作 .

  • 9

    我遇到过类似的问题

    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

    First one 是通过在脚本预处理器中模拟 .css 本身来解决的 .

    通过使用 unmockedModulePathPatterns 从自动锁定中排除装饰器来解决 Second one

    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
    
  • 0

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

    webpack-babel-jest

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

  • 4

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

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

相关问题