用玩笑模拟 setTimeout

Igo*_*ler 3 javascript unit-testing mocking settimeout jestjs

我有一个用 React.JS 制作的网站,它不断地为正在发生的所有事情(但什么也没有)发出事件。例如,用户在表单中键入内容,发出事件。用户将焦点放在某个字段上并且一段时间内没有执行任何操作,我们再次发出一个事件。这个想法是为了了解客户的行为。

我有一个以前用作 的按钮<Button onClick={(e)=>handler(e)}/>。我必须对按钮进行去抖并将其更改为<Button onClick={(e)=>setTimeout(handler(e), 1000)}/>。否则,用户不明白发生了什么。

现在,我正在尝试将测试调整为:

  it('displays similar listings', async () => {
    const renderResult = renderVdp(renderParams);

    await new Promise((resolve) => setTimeout(resolve, 1000));
    await waitFor(async () => {
      expect(renderResult.getAllByText('2017 BMW M3')).toHaveLength(4);
    });
  });
Run Code Online (Sandbox Code Playgroud)

通过添加之前的相关测试,我能够保持原始测试的工作await new Promise((resolve) => setTimeout(resolve, 1000));。如果没有它,测试将收到下一个发出的事件,该事件不是作为单击按钮的响应而发出的事件。

我想使用玩笑计时器模拟或类似的东西,而不是在我的测试中实际引入延迟。我尝试过使用jest.useFakeTimers(),但它不能按我的需要工作。我的期望落空了。

建议?

Per*_*ril 8

一旦使用假定时器,您就可以控制何时运行它们。尝试在渲染后运行它们:

it('displays similar listings', async () => {
    jest.useFakeTimers()
    const renderResult = renderVdp(renderParams);
    jest.runAllTimers();
    expect(renderResult.getAllByText('2017 BMW M3')).toHaveLength(4);
  });
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,您可以随时使用更“激进”的模拟:

global.setTimeout = jest.fn(cb => cb());
Run Code Online (Sandbox Code Playgroud)

我会在测试设置beforeEach/中执行此操作beforeAll,并在测试拆卸afterEach/中回滚到原始 setTimeoutafterAll

  • 这是一个打字稿错误。我不确定 setTimeout 的签名是如何定义的。您可以随时添加@ts-ignore来查看它是否有效。 (2认同)