在 mocha 测试中使用 webpack 别名

59

我正在工作中开发一个React/Redux/Webpack的Web应用程序,并开始使用Mocha进行测试。

我遵循了Redux文档中编写测试的说明,但现在我遇到了一个关于webpack别名的问题。

例如,看一下我的一个动作创建器的测试文件中的导入部分:

import expect       from 'expect'                 // resolves without an issue
import * as actions from 'actions/app';           // can't resolve this alias
import * as types   from 'constants/actionTypes'; // can't resolve this alias

describe('Actions', () => {
  describe('app',() => {
    it('should create an action with a successful connection', () => {

      const host = '***************',
            port = ****,
            db = '******',
            user = '*********',
            pass = '******';

      const action = actions.createConnection(host, port, db, user, pass);

      const expectedAction = {
        type: types.CREATE_CONNECTION,
        status: 'success',
        payload: { host, port, database, username }
      };

      expect(action).toEqual(expectedAction);
    });
  });
});

正如评论所述,当我的导入语句引用别名依赖项时,mocha无法解析它们。

因为我对webpack还很陌生,这里是我的webpack.config.js

module.exports = {
  devtool: 'eval-source-map',
  entry: [
    'webpack-hot-middleware/client',
    './src/index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  resolve: {
    extensions : ['', '.js', '.jsx'],
    alias: {
      actions: path.resolve(__dirname, 'src', 'actions'),
      constants: path.resolve(__dirname, 'src', 'constants'),
      /* more aliases */
    }
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  module: {
    loaders: [{
      test: /\.js$/,
      loaders: ['babel'],
      exclude: /node_modules/,
      include: __dirname
    }]
  }
};

另外,我正在使用命令npm test来运行mocha,这是我在package.json中使用的脚本。

 {   
   "scripts": {
     "test": "mocha ./src/**/test/spec.js --compilers js:babel-core/register --recursive"
   }
 }

所以这里是我卡住的地方。我需要在 mocha 运行时将 webpack 的别名包含进去。

我也遇到了同样的问题,你找到解决方法了吗? - Issam Zoli
是的,我刚刚发布了我的答案。你的结果可能会有所不同。 - Danny Delott
8个回答

42

好的,我意识到我给别名的所有东西都在src/目录中,所以我只需要修改我的npm run test脚本。

{   
  "scripts": {
    "test": "NODE_PATH=./src mocha ./src/**/test/spec.js --compilers js:babel-core/register --recursive"
  }
}

可能不适用于每个人,但这解决了我的问题。


谢谢,我会尝试的。 - Issam Zoli
我的所有文件都在“src”文件夹中,但是我不确定如何将你的修复方法应用到我的测试脚本上:“find ./src -name '*.test.js' | xargs mocha --require babel-core/register” - azium
这是一个非常出色的解决方案,特别是与模拟和代理要求相比较! - mikeycgto
这对我单次测试运行非常有效,但我无法成功地在别名目录中观察文件,你有没有成功观察的经验? - jmancherje
1
我开始使用 mocha-webpack 替代这个解决方法。https://github.com/zinserjan/mocha-webpack - Danny Delott

15

我点击了你的链接,根据那里的用户信息和你在这里的用户信息,看起来你是插件的作者,所以我进行了编辑,因为在回答中提到你创建的软件而*没有明确说明你是作者是违反 SO 规则的(这样做被认为是垃圾邮件,并且会受到严厉的惩罚)。如果你不是作者,可以回滚我的编辑,但请确保澄清,否则下一个点击链接的人可能会得出与我相同的推断。 - Louis
此外,当前答案存在较大的链接依赖性。添加有关如何安装和使用插件的信息将有助于解决这个问题。 - Louis
4
我目前正在开发中使用它,但未用于生产。它似乎完全符合预期。我很喜欢别名,并认为使用Babel插件来解决这个问题是正确的方法。我还没有查看源代码或其他内容,但目前一切都运行良好。 - Ryan Ore

5

我也遇到了同样的问题,但是通过这个插件,我解决了它。

https://www.npmjs.com/package/babel-plugin-webpack-aliases

你的 "mocha" 执行命令没有读取 webpack.config.js 文件,所以无法解析别名。
通过设置此插件,在使用 "babel-core/register" 编译时会考虑 webpack.config.js 文件。因此,在测试过程中别名也将有效。

npm i -D babel-plugin-webpack-aliases

并将此设置添加到.babelrc

{
    "plugins": [
        [ "babel-plugin-webpack-aliases", { "config": "./webpack.config.js" } ] 
    ]
}

4
我认为我解决了这个问题。你应该使用两个包:mock-requireproxyquire
假设你有一个像这样的js文件: app.js
import action1 from 'actions/youractions';   

export function foo() { console.log(action1()) }; 

你的测试代码应该像这样编写:

app.test.js

import proxyquire from 'proxyquire';
import mockrequire from 'mock-require';

before(() => {
  // mock the alias path, point to the actual path
  mockrequire('actions/youractions', 'your/actual/action/path/from/your/test/file');
  // or mock with a function
  mockrequire('actions/youractions', {actionMethod: () => {...}));

let app;
beforeEach(() => {
  app = proxyquire('./app', {});
});

//test code
describe('xxx', () => {
  it('xxxx', () => {
    ...
  });
});

文件树

app.js
  |- test
    |- app.test.js

首先在before函数中使用mock-require模拟别名路径,然后在beforeEach函数中使用proxyquire模拟测试对象。


4
丹尼的回答非常好。但我的情况有点不同。我使用Webpack的 resolve.alias 来使用 src 文件夹下的所有文件。
resolve: {
  alias: {
    '-': path.resolve(__dirname, '../src'),
  },
},

我希望你能为我的模块使用特殊前缀,例如:

import App from '-/components/App';

为了测试这样的代码,我需要在运行mocha测试之前添加一个命令ln -sf src test/alias/-,并使用Danny想出的NODE_PATH=./test/alias技巧。因此,最终脚本应该像这样:
{   
  "scripts": {
    "test": "ln -sf src test/alias/-; NODE_PATH=./test/alias mocha ./src/**/test/spec.js --compilers js:babel-core/register --recursive"
  }
}

PS:

我使用了-,因为像@~这样美丽的字符不够安全。我在这里找到了安全字符的答案。


2
我假设您的 mocha.opts 文件中已经添加了 --require babel-register。您可以使用 Babel 模块解析插件https://github.com/tleunen/babel-plugin-module-resolver。这使您能够在 .babelrc 中设置别名,类似于您的 webpack 别名。
{
  "plugins": [
    ["module-resolver", {
       "alias": {
         "actions": "./src/actions",
         "constants": "./src/constants"
       }
    }]
  ]
}

1

为了将别名统一放置在一个地方,比如config/webpack.common.js文件中。

resolve: {
    alias: {
        '~': path.resolve(__dirname, './../src/app')
    }
}

然后安装 babel-plugin-webpack-alias插件。

npm i babel-plugin-webpack-alias --save-dev

然后在.babelrc中放置以下内容:
{
    "presets": ["env"],
    "plugins": [
        ["babel-plugin-webpack-alias", {
            "config": "./config/webpack.common.js" // path to your webpack config
        }]
    ]
}

1
我曾遇到完全相同的问题。似乎无法在 require.js 或 node 的 require 中使用 webpack 别名。
最终,我在单元测试中使用 mock-require,并手动替换路径,如下所示:
var mock = require('mock-require');

mock('actions/app', '../../src/actions/app');

mock-require是一个很好的工具,因为您很可能想要模拟大多数依赖项,而不是使用来自实际脚本的代码。


当我使用mock-require时,似乎没有起作用,错误仍然显示找不到模块“actions/xxx”。 - zzm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接