如何在 Jest 中正确使用 Promises 和 Timer [英] How to properly use Promises and Timers with Jest

查看:18
本文介绍了如何在 Jest 中正确使用 Promises 和 Timer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜索了 SO 和 Google,发现了很多类似的问题和答案,但似乎没有一个能帮助我解决我的问题.

I have searched both SO and Google and found a lot of similar questions and answers, but none of them seems to have helped me solve my issue.

我正在尝试编写一些需要模拟异步轮询函数的测试用例.但无论我做什么,我都会得到:

I am attempting to write some test cases where I need to mock an async polling function. But no matter what I do I get:

在 jest.setTimeout.Timeout 指定的 5000 毫秒超时内未调用异步回调

我设置了一些最小的测试用例来重现问题:

I set up some minimal test cases the reproduce the problem:

jest.useFakeTimers();

describe('timers test', () => {
  it('plain timer works as expected', () => {
    const mock = jest.fn();
    setTimeout(mock, 5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution results in a jest timeout error', async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve) => setTimeout(resolve, 500));
    });

    const handler = jest.fn();

    await mock().then(handler);

    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection results in a jest timeout error', async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve, reject) => setTimeout(reject, 500));
    });

    const handler = jest.fn();

    await mock().catch(handler);

    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });
});

有人可以解释我做错了什么以及为什么吗?

Can someone explain what I am doing wrong and why?

推荐答案

因此,在@Bergi 的后续评论中,我认为 done 实际上也不是必需的.我只需要重新订购一些东西.然后,我在测试进一步强调这一点的承诺链时遇到了类似的问题,因此我为此添加了一些案例.

So with a follow up comment from @Bergi, I relaized the done wasn't actually necessary either. I just needed to re-order some things. I then ran into a similar issue when testing chains of promises that further highlighted this so I added some cases for that.

jest.useFakeTimers();

describe('timers test', () => {
  it('Using a plain timer works as expected', () => {
    const mock = jest.fn();
    setTimeout(mock, 5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution', async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve) => setTimeout(resolve, 500));
    });

    const handler = jest.fn();

    const actual = mock().then(handler);
    jest.runAllTimers();
    await actual;

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection', async () => {
    const mock = jest.fn(() => {
      return new Promise((resolve, reject) => setTimeout(reject, 500));
    });

    const handler = jest.fn();

    const actual = mock().catch(handler);
    jest.runAllTimers();
    await actual;

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolve -> delay -> resolve chain', async () => {
    const mockA = jest.fn(() => {
      return Promise.resolve();
    });

    const mockB = jest.fn(() => {
      return new Promise((resolve, reject) => {
        setTimeout(resolve, 500);
      });
    });

    const handler = jest.fn();

    const actual = mockA()
      .then(() => {
        const mockProm = mockB();
        jest.runAllTimers();
        return mockProm;
      })
      .then(handler);

    jest.runAllTimers();
    await actual;

    expect(mockA).toHaveBeenCalled();
    expect(mockB).toHaveBeenCalled();
    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolve -> delay -> reject chain', async () => {
    const mockA = jest.fn(() => {
      return Promise.resolve();
    });

    const mockB = jest.fn(() => {
      return new Promise((resolve, reject) => {
        setTimeout(reject, 500);
      });
    });

    const handler = jest.fn();

    const actual = mockA()
      .then(() => {
        const mockProm = mockB();
        jest.runAllTimers();
        return mockProm;
      })
      .catch(handler);


    await actual;

    expect(mockA).toHaveBeenCalled();
    expect(mockB).toHaveBeenCalled();
    expect(handler).toHaveBeenCalled();
  });
});

<小时>

@Bergi' 评论引导我找到解决方案.我最终使用了 done 函数,并删除了 await.这似乎至少在这个最小的测试用例中有效.


@Bergi' comment led me to the solution. I ended up making use of the done function, and removing the await. This seems to work at least in this minimal test case.

jest.useFakeTimers();

describe('timers test', () => {
  it('plain timer works as expected', () => {
    const mock = jest.fn();
    setTimeout(mock, 5000);

    jest.runAllTimers();
    expect(mock).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise resolution results in a jest timeout error', async (done) => {
    const mock = jest.fn().mockImplementation(() => {
      return new Promise((resolve) => setTimeout(resolve, 500));
    });

    // make the handler invoke done to replace the await    
    const handler = jest.fn(done);

    mock().then(handler);
    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });

  it('Using a timer to mock a promise rejection results in a jest timeout error', async (done) => {
    const mock = jest.fn().mockImplementation(() => {
      return new Promise((resolve, reject) => setTimeout(reject, 500));
    });

    // make the handler invoke done to replace the await
    const handler = jest.fn(done);

    mock().catch(handler);
    jest.runAllTimers();

    expect(handler).toHaveBeenCalled();
  });
});

这篇关于如何在 Jest 中正确使用 Promises 和 Timer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆