我怎样才能用Jest模拟一个ES6模块导入?
我开始认为这是不可能的,但我仍然要问。
我想testing一个我的ES6模块以特定的方式调用另一个ES6模块。 与茉莉花这是超级简单 –
应用程序代码:
// myModule.js import dependency from './dependency'; export default (x) => { dependency.doSomething(x * 2); }
和testing代码:
//myModule-test.js import myModule from '../myModule'; import dependency from '../dependency'; describe('myModule', () => { it('calls the dependency with double the input', () => { spyOn(dependency, 'doSomething'); myModule(2); expect(dependency.doSomething).toHaveBeenCalledWith(4); }); });
与Jest相当的是什么? 我觉得这是一件很简单的事情,但我一直在试图弄清楚自己的头发。
我最接近的是用require
s来replaceimport
,并将它们移动到testing/函数中。 这两者都不是我想要做的事情。
// myModule.js export default (x) => { const dependency = require('./dependency'); // yuck dependency.doSomething(x * 2); } //myModule-test.js describe('myModule', () => { it('calls the dependency with double the input', () => { jest.mock('../dependency'); myModule(2); const dependency = require('../dependency'); // also yuck expect(dependency.doSomething).toBeCalledWith(4); }); });
对于奖励积分来说,我很乐意在dependency.js
里面的函数是一个默认的导出的时候使整个事情工作。 不过,我知道在Jasmine中,对默认出口进行间谍活动并不起作用(或者至less我永远无法起作用),所以我并不希望在Jest中也有可能。
我已经能够通过使用涉及import *
的黑客来解决这个问题。 它甚至适用于命名和默认导出!
对于一个命名的导出:
// dependency.js export const doSomething = (y) => console.log(y) // myModule.js import { doSomething } from './dependency'; export default (x) => { doSomething(x * 2); } // myModule-test.js import myModule from '../myModule'; import * as dependency from '../dependency'; describe('myModule', () => { it('calls the dependency with double the input', () => { dependency.doSomething = jest.fn(); // Mutate the named export myModule(2); expect(dependency.doSomething).toBeCalledWith(4); }); });
或者对于默认导出:
// dependency.js export default (y) => console.log(y) // myModule.js import dependency from './dependency'; // Note lack of curlies export default (x) => { dependency(x * 2); } // myModule-test.js import myModule from '../myModule'; import * as dependency from '../dependency'; describe('myModule', () => { it('calls the dependency with double the input', () => { dependency.default = jest.fn(); // Mutate the default export myModule(2); expect(dependency.default).toBeCalledWith(4); // Assert against the default }); });
正如Mihai Damian在下面正确地指出的那样,这正在改变dependency
的模块对象,所以它会泄漏到其他testing中。 所以,如果你使用这种方法,你应该存储原始值,然后在每次testing之后再次设置它。 这就是为什么Sinon有restore
方法!
你必须嘲笑模块,并设置自己的间谍:
import myModule from '../myModule'; import dependency from '../dependency'; jest.mock('../dependency', () => ({ doSomething: jest.fn() })) describe('myModule', () => { it('calls the dependency with double the input', () => { myModule(2); expect(dependency.doSomething).toBeCalledWith(4); }); });
增加更多的安德烈亚斯的答案。 我有与ES6代码相同的问题,但不想mutateimport。 那看起来很黑。 所以我做了这个
import myModule from '../myModule'; import dependency from '../dependency'; jest.mock('../dependency'); describe('myModule', () => { it('calls the dependency with double the input', () => { myModule(2); }); });
并在“__ mocks __”文件夹中添加dependency.js,并与dependency.js平行。 这对我有效。 此外,这给了我select从模拟实施返回合适的数据。 确保你给你想要模拟的模块提供正确的path。
使用jest来模拟ES6依赖模块的默认导出:
import myModule from '../myModule'; import dependency from '../dependency'; jest.mock('../dependency'); // If necessary, you can place a mock implementation like this: dependency.mockImplementation(() => 42); describe('myModule', () => { it('calls the dependency once with double the input', () => { myModule(2); expect(dependency).toHaveBeenCalledTimes(1); expect(dependency).toHaveBeenCalledWith(4); }); });
其他选项不适合我的情况。