如何使用Jest同时模拟同名的命名空间与函数?
问题:Jest模拟兼具函数与命名空间特性的@distube/ytdl-core库
我正在测试自行编写的YouTube下载器,工具基于@distube/ytdl-core库开发。该库导出的ytdl变量同时具备函数调用能力和命名空间特性(挂载了getInfo等方法),导致我在使用Jest模拟时遇到阻碍。
库的导出逻辑示例
const ytdl = (link, options) => { const stream = createStream(options); ytdl.getInfo(link, options).then( info => { downloadFromInfoCallback(stream, info, options); }, stream.emit.bind(stream, "error"), ); return stream; }; module.exports = ytdl; ytdl.getBasicInfo = getInfo.getBasicInfo; ytdl.getInfo = getInfo.getInfo; // 其他挂载的方法...
当前困境
- 无法直接模拟整个
ytdl对象:只能通过jest.spyOn(ytdl, 'methodName')模拟单个挂载方法,却没法模拟ytdl()函数本身的调用 - 找到的Stack Overflow相关问题无有效解决方案,尝试过的方法均不生效
- 当前只能通过将
ytdl挂载到自定义对象的方式实现部分模拟:
// 项目中的写法 const distube = {}; distube.ytdl = require("@distube/ytdl-core"); // 测试文件中的模拟 jest.spyOn(distube, 'ytdl').mockImplementation(() => { /* 模拟逻辑 */ });
- 直接使用
jest.mock模拟@distube/ytdl-core模块,对Express应用中的ytdl实例无效(应用使用light-my-request运行测试)
Express测试代码示例(基于light-my-request)
const inject = require('light-my-request'); it('should treat empty strings as no value)', async () => { const result = await inject(app, { method: 'POST', url: '/', headers: { 'Accept': 'multipart/form-data' }, payload: { url: PLAYLIST_URL+VALID_PLAYLIST_ID, limit: '' }, }); expect(result).toBeArray(); });
当前临时解决方案(非理想)
只能通过覆盖真实ytdl对象的方式同时模拟函数和方法:
distube.ytdl = () => { // 函数模拟逻辑 }; distube.ytdl.getInfo = () => ('false');
期望实现的模拟方案
希望找到能同时模拟ytdl()函数和其挂载方法(如getInfo)的方案,类似如下写法:
jest.mock(ytdl, () => { const ytdl = jest.fn().mockImplementation(); ytdl.getInfo = jest.fn().mockImplementation(); return ytdl; });
内容的提问来源于stack exchange,提问作者Rob Gravelle
相关产品推荐
相关产品推荐

