如何进行一个在检查元素外观之前等待 5 秒的测试(React 测试库)

Mar*_*mes 2 javascript unit-testing reactjs jestjs react-testing-library

在我的反应组件中,我有一个 5 秒后出现的元素。

我想做一个测试,检查 5 秒后元素是否出现jest fake timers,但无法使其工作......

我在这里做错了什么?

其中一个示例不起作用:

it('check step 2 labels text, status "Submitted"', async () => {
    render(<ProgressIndicator appStatus="submitted" />);

    jest.advanceTimersByTime(5005);
    await waitFor(() => {
      expect(
        screen.getByText('Beep. Boop. Still doing our thing here.'),
      ).toBeInTheDocument();
    });

    await waitFor(() => {
      expect(screen.getByText('Verifying identity...')).toBeInTheDocument();
    });
  });
Run Code Online (Sandbox Code Playgroud)

第二个例子:

it('check step 2 labels text, status "Submitted"', async () => {
    render(<ProgressIndicator appStatus="submitted" />);

    act(() => {
      jest.advanceTimersByTime(5005);
    });

    expect(
      screen.getByText('Beep. Boop. Still doing our thing here.'),
    ).toBeInTheDocument();
    expect(screen.getByText('Verifying identity...')).toBeInTheDocument();
  });

Run Code Online (Sandbox Code Playgroud)

Sub*_*aik 7

await findBy使用查询的一般经验法则await waitFor是您应该使用

\n
\n

await findBy当您期望出现某个元素但 DOM 的更改可能不会立即发生时。

\n
\n
\n

await waitFor你有一个模拟 API 调用的单元测试时,你需要等待你的模拟承诺解析。

\n
\n

dom-testing-library的官方文档中也提到了同样的内容。

\n
\n

现在谈到您关心的问题,您需要使用jest.useFakeTimer()启用假计时器,这将有助于模拟 setTimeout 和其他计时器函数。

\n

官方文档中也提到了同样的事情。

\n

useFakeTimer 使用异步方法,但是,如果我们想要使用getBy查询等同步方法,那么我们必须使用jest.advanceTimersByTime(5000)将测试提前 5(任何指定时间)秒。(下面给出的例子)

\n

在下面的例子中,我重现了您提出的问题。我想这可能会有所帮助。

\n
import { useState } from \'react\';\nimport { act, render, screen, waitForElementToBeRemoved } from \'@testing-library/react\';\nimport userEvent from \'@testing-library/user-event\';\n\nconst data = {\n  name: \'subrato\',\n  age: 24,\n};\n\n\nfunction App() {\n  const [myData, setState] = useState({});\n  const [loading, setLoading] = useState(false);\n\n  function clickHandler() {\n    setLoading(true);\n    setTimeout(() => {\n      setState(data);\n      setLoading(false);\n    }, 5000);\n  }\n\n  return (\n    <div className=\'App\'>\n      {loading && <div aria-label=\'loading\'>loading....</div>}\n      <p>{myData?.name}</p>\n      <p>{myData?.age}</p>\n      <button onClick={clickHandler}>Click me</button>\n    </div>\n  );\n}\ndescribe(\'Test my app\', () => {\n  beforeEach(() => {\n    jest.useFakeTimers();\n  });\n\n  afterEach(() => {\n    jest.useRealTimers();\n  });\n\n  it(\'display data\', async () => {\n    render(<App />);\n\n    userEvent.click(screen.getByText(\'Click me\'));\n\n    expect(screen.getByLabelText(/loading/i)).toBeInTheDocument();\n\n    expect(await screen.findByText(\'subrato\')).toBeInTheDocument();\n    expect(screen.getByText(\'24\')).toBeInTheDocument();\n   \n  });\n\n  it(\'display data second time\', async () => {\n    render(<App />);\n\n    userEvent.click(screen.getByText(\'Click me\'));\n\n    expect(screen.getByLabelText(/loading/i)).toBeInTheDocument();\n\n    act(() => jest.advanceTimersByTime(5000));\n\n    expect(screen.getByText(\'subrato\')).toBeInTheDocument();\n    expect(screen.getByText(\'24\')).toBeInTheDocument();\n   \n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

测试结果

\n
 PASS  src/TimerExample.spec.tsx (9.001 s)\n  Test my app\n    \xe2\x88\x9a display data (487 ms)\n    \xe2\x88\x9a display data second time (35 ms)\n\nTest Suites: 1 passed, 1 total\nTests:       2 passed, 2 total\nSnapshots:   0 total\nTime:        14.997 s\nRan all test suites matching /TimerExample.spec.tsx/i.\n
Run Code Online (Sandbox Code Playgroud)\n

  • 我很高兴知道这个解决方案是否能解决您的问题。 (2认同)