You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 19:17:45