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

Jest中带done回调的测试在前序测试失败后异常失败问题

Jest单条带done回调的测试失败导致后续所有测试失败的原因与解决方法

核心原因

当expect断言失败时会直接抛出异常,中断当前测试函数的执行,导致后续的done()函数从未被调用:

  • Jest会将没有调用done()的异步测试标记为超时失败
  • 前序测试未做上下文清理(比如map实例未销毁、jest mock未还原、事件监听残留)会进一步污染后续测试的运行环境,最终表现为所有带done的测试全部失败

问题代码示例

可正常运行的原始测试

describe('Map#isRotating', () => {
    test('returns false by default', done => {
        const map = createMap();
        expect(map.isRotating()).toBe(false);
        map.remove();
        done();
    });

    test('returns true during a camera rotate animation', done => {
        const map = createMap();

        map.on('rotatestart', () => {
            expect(map.isRotating()).toBe(true);
        });

        map.on('rotateend', () => {
            expect(true).toBe(false);
            map.remove();
            done();
        });

        map.rotateTo(5, {duration: 0});
    });

    test('returns true when drag rotating', done => {
        const map = createMap();

        // Prevent inertial rotation.
        jest.spyOn(browser, 'now').mockImplementation(() => { return 0; });

        map.on('rotatestart', () => {
            expect(map.isRotating()).toBe(true);
        });

        map.on('rotateend', () => {
            expect(map.isRotating()).toBe(false);
            map.remove();
            done();
        });

        simulate.mousedown(map.getCanvas(), {buttons: 2, button: 2});
        map._renderTaskQueue.run();

        simulate.mousemove(map.getCanvas(), {buttons: 2, clientX: 10, clientY: 10});
        map._renderTaskQueue.run();

        simulate.mouseup(map.getCanvas(),   {buttons: 0, button: 2});
        map._renderTaskQueue.run();
    });
});

修改后触发批量失败的测试代码

describe('Map#isRotating', () => {
    test('returns false by default', done => {
        const map = createMap();
        expect(true).toBe(false);
        map.remove();
        done();
    });

修复方案

方案1:给done回调的测试增加try/catch包裹

保证无论断言是否成功,done()都会被调用,错误会通过done()的参数传递给Jest做标记:

test('returns false by default', done => {
  try {
    const map = createMap();
    expect(true).toBe(false);
    map.remove();
    done();
  } catch (err) {
    done(err);
  }
});

方案2:改用async/await异步写法(更推荐)

Jest原生支持async异步测试,不需要手动调用done回调,断言失败会自动终止测试并标记结果,不会出现回调未执行的问题:

test('returns false by default', async () => {
  const map = createMap();
  expect(map.isRotating()).toBe(false);
  map.remove();
});

方案3:增加全局清理逻辑

在afterEach钩子中统一做上下文清理,避免前序测试的残留内容影响后续用例:

afterEach(() => {
  // 还原所有jest mock
  jest.restoreAllMocks();
  // 销毁残留的map实例
  if (map) map.remove();
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 19:27:06