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

Jest测试中emit error未触发预期错误处理函数的原因排查

问题根因

  • mock实例缺失方法,事件触发无效:你给fs.createWriteStream的mock返回值仅定义了on、close两个方法,测试代码中调用writer.emit('error')时触发的是不存在的方法,绑定的错误回调自然不会执行。
  • pipeHandler赋值时机错误:beforeEach执行阶段就已经完成了axios的mock注入,此时pipeHandler还未在it块中赋值,传入mock的是undefined,你写的错误触发逻辑根本不会运行。
  • 冗余mock函数无绑定:你定义的writerErrorFn、dataErrorFn没有和事件回调逻辑做任何关联,永远不会被调用,基于这些函数的断言必然失败。

修复方案

不需要完全重构测试,调整mock逻辑和事件触发方式即可:

describe('fetchData', () => {
  let mockWriterEventHandlers = {};
  let mockDataEventHandlers = {};
  let writerCloseFn;

  beforeEach(() => {
    mockWriterEventHandlers = {};
    mockDataEventHandlers = {};

    // 绑定事件时把回调存入对应事件的handler对象
    const dataOnFn = jest.fn((e, cb) => {
      mockDataEventHandlers[e] = cb;
    });
    const writerOnFn = jest.fn((e, cb) => {
      mockWriterEventHandlers[e] = cb;
    });
    writerCloseFn = jest.fn();

    // 不需要实际执行pipe逻辑,我们手动触发事件即可
    axios.mockImplementationOnce(() => ({
      status: 200,
      data: {
        pipe: jest.fn(),
        on: dataOnFn,
      },
      headers: { 'content-length': 100 },
    }));
    fs.createWriteStream.mockImplementationOnce(() => ({
      on: writerOnFn,
      close: writerCloseFn,
    }));

    jest.spyOn(console, 'info').mockImplementation(() => {});
    jest.spyOn(console, 'log').mockImplementation(() => {});
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.useRealTimers();
    jest.clearAllMocks();
  });

  it('handles errors from the writer', async () => {
    expect.assertions(2);
    const testError = new Error('bang');
    // 先启动下载逻辑,完成所有事件绑定
    const downloadPromise = downloadMtgJsonZip();
    // 手动触发writer的error事件,执行业务代码中绑定的回调
    mockWriterEventHandlers.error(testError);
    
    try {
      await downloadPromise;
    } catch (err) {
      // 校验错误被正确抛出
      expect(err).toEqual(testError);
      // 校验writer.close按预期调用
      expect(writerCloseFn).toHaveBeenCalled();
    }
  });
});

如果确实需要验证pipe调用后的逻辑,可以把pipe的mock改为接收writer参数后执行对应逻辑,注意要在mock中动态读取pipeHandler,不要在beforeEach阶段就固化值即可。

内容的提问来源于stack exchange,提问作者AncientSwordRage

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 07:24:02