簡體   English   中英

Mocking setTimeout with jest

[英]Mocking setTimeout with jest

我有一個用 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);
    });
  });

我能夠通過添加await new Promise((resolve) => setTimeout(resolve, 1000));來保持原始測試的工作。 在相關測試之前。 沒有它,測試會收到下一個發出的事件,這不是作為單擊按鈕的響應而發出的事件。

我想使用開玩笑的計時器 mocking 或類似的東西,而不是在我的測試中實際引入延遲。 我曾嘗試使用jest.useFakeTimers() ,但它不能按我的需要工作。 我的期望失敗了。

建議?

一旦你使用了假計時器,你就可以控制何時運行它們。 渲染后嘗試運行它們:

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

如果這不起作用,您可以隨時使用更“激進”的模擬:

global.setTimeout = jest.fn(cb => cb());

我會在測試設置beforeEach / beforeAll中執行此操作,並在測試拆解afterEach / afterAll中回滾到原始 setTimeout

如果我看不到代碼,很難說出測試應該是什么樣子。

如果您的組件有點像這樣工作:

const SetTimeoutComponent = () => {
  const [content, setContent] = React.useState<string[]>([]);

  const handleButtonClick = (event: React.MouseEvent<HTMLElement>) => {
    setContent([
        '2017 BMW M3',
        '2017 BMW M3',
        '2017 BMW M3',
        '2017 BMW M3'
    ])
  }

  return (
    <div>
      <button onClick={(e)=>setTimeout(() => handleButtonClick(e), 1000)}>
        Set timeout with state update
      </button>
      <div>
        {content.map((item, index) => (
            <div key={index}>{item}</div>
        ))}
      </div>
    </div>
  );
};

然后您可以按如下方式對其進行測試:

it('displays similar listings', async () => {
  render(<TestedComponent />);
  const setTimeoutButton = screen.getByRole('button');

  jest.useFakeTimers();
  fireEvent.click(setTimeoutButton);
  act(() => {
    jest.runAllTimers();
  });
  expect(screen.getAllByText('2017 BMW M3')).toHaveLength(4);

  jest.useRealTimers();
});

您可以在我的帖子中查看更多信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM