这个语法:
import something from 'myModule';
...是将something 绑定到'myModule' 的default 导出的ES6 语法。
如果模块是 ES6 模块,那么您可以像这样对模块的 default 导出存根:
import * as myModule from 'myModule';
const sinon = require('sinon');
// ...
const stub = sinon.stub(myModule, 'default');
...但这仅在 'myModule' 是 ES6 模块时才有效。
在这种情况下,'lodash/debounce' 不是 ES6 模块,它是预编译的。最后一行是这样的:
module.exports = debounce;
...表示模块导出是去抖动功能。
这意味着为了存根'lodash/debounce',您必须模拟整个模块。
Sinon 不提供模块级别的模拟,因此您需要使用类似proxyquire:
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const debounceStub = sinon.stub().returnsArg(0);
const code = proxyquire('[path to your code]', { 'lodash/debounce': debounceStub })
...或者如果你使用Jest,你可以使用jest.mock:
jest.mock('lodash/debounce', () =>
jest.fn((func, ms) => func) // <= mock debounce to simply return the function
);
详情
仅当模块是 ES6 模块时才对模块的 default 导出进行存根处理的原因是编译期间发生的事情。
ES6 语法被编译成 pre-ES6 JavaScript。例如,Babel 会变成这样:
import something from 'myModule';
...进入这个:
var _myModule = _interopRequireDefault(require("myModule"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ?
obj : // <= return the result of require("myModule") if it is an ES6 module...
{ default: obj }; // <= otherwise set it to the default property of a wrapper object
}
...所以如果'myModule' 是一个 ES6 模块,它会直接返回...但如果不是,则互操作会返回一个包装对象。
由于每个import 获得不同的包装对象,因此更改一个default 属性不会影响任何其他default 属性。