ensure函数_使用webpack的require.ensure函数为javascript模块编写测试

I am running mocha tests on my server, testing source scripts an isolated unit test manner.

One of the scripts I am testing makes a call to Webpack's require.ensure function, which is useful for creating code-splitting points in the application when it gets bundled by Webpack.

The test I have written for this script does not run within a Webpack context, therefore the require.ensure function does not exist, and the test fails.

I have tried to create some sort of polyfill/stub/mock/spy for this function but have had no luck whatsoever.

There is a package, webpack-require, which does allow for the creation of a webpack context. This can work but it is unacceptably slow. I would prefer to have some sort of lightweight polyfill targeting the require.ensure function directly.

Any recommendations? :)

Here is a very basic starting point mocha test.

The mocha test loads a contrived module containing a method which returns true if require.ensure is defined.

foo.js

export default {

requireEnsureExists: () => {

return typeof require.ensure === 'function';

}

};

foo.test.js

import { expect } from 'chai';

describe('When requiring "foo"', () => {

let foo;

before(() => {

foo = require('./foo.js');

});

it('The requireEnsureExists() should be true', () => {

expect(foo.requireEnsureExists()).to.be.true;

});

});

解决方案

Ok, I finally have an answer for this after much research and deliberation.

I initially thought that I could solve this using some sort of IoC / DI strategy, but then I found the source code for Node JS's Module library which is responsible for loading modules. Looking at the source code you will notice that the 'require' function for modules (i.e. foo.js in my example) get created by the _compile function of NodeJs's module loader. It's internally scoped and I couldn't see an immediate mechanism by which to modify it.

I am not quite sure how or where Webpack is extending the created "require" instance, but I suspect it is with some black magic. I realised that I would need some help to do something of a similar nature, and didn't want to write a massive block of complicated code to do so.

Then I stumbled on rewire...

Dependency injection for node.js applications.

rewire adds a special setter and getter to modules so you can modify their behaviour for better unit testing. You may

inject mocks for other modules

leak private variables

override variables within the module.

rewire does not load the file and eval the contents to emulate node's require mechanism. In fact it uses node's own require to load the module. Thus your module behaves exactly the same in your test environment as under regular circumstances (except your modifications).

Perfect. Access to private variables is all that I need.

After installing rewire, getting my test to work was easy:

foo.js

export default {

requireEnsureExists: () => {

return typeof require.ensure === 'function';

}

};

foo.test.js

import { expect } from 'chai';

import rewire from 'rewire';

describe('When requiring "foo"', () => {

let foo;

before(() => {

foo = rewire('./foo.js');

// Get the existing 'require' instance for our module.

let fooRequire = moduletest.__get__('require');

// Add an 'ensure' property to it.

fooRequire.ensure = (path) => {

// Do mocky/stubby stuff here.

};

// We don't need to set the 'require' again in our module, as the above

// is by reference.

});

it('The requireEnsureExists() should be true', () => {

expect(foo.requireEnsureExists()).to.be.true;

});

});

Aaaaah.... so happy. Fast running test land again.

Oh, in my case it's not needed, but if you are bundling your code via webpack for browser based testing, then you may need the rewire-webpack plugin. I also read somewhere that this may have problems with ES6 syntax.

Another note: for straight up mocking of require(...) statements I would recommend using mockery instead of rewire. It's less powerful than rewire (no private variable access), but this is a bit safer in my opinion. Also, it has a very helpful warning system to help you not do any unintentional mocking.

Update

I've also seen the following strategy being employed. In every module that uses require.ensure check that it exists and polyfill it if not:

// Polyfill webpack require.ensure.

if (typeof require.ensure !== `function`) require.ensure = (d, c) => c(require);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值