React 测试库在初始渲染后未使用 getAllByTestId 找到元素

use*_*707 8 javascript testing reactjs jestjs react-testing-library

我有一个非常简单的组件,我试图模拟 API 调用来获取一些稍有延迟的电影。

我想编写一个测试来测试电影是否被收集然后渲染到屏幕上。

我试图用来screen.getAllByTestId做到这一点,但它总是失败。就好像它没有重新渲染,因此没有获得更新的更改。

我在元素上添加了一个 testid,并且可以在 DOM 中看到它们。

任何人都可以帮忙解释为什么他们出现后找不到他们吗?

在此输入图像描述

这是完整的组件代码...

import './App.css';
import { useEffect, useState } from 'react';

function App() {
  const [movies, setMovies] = useState([]);

  useEffect(() => {
    // simulate API call to get
    setTimeout(() => {
      const movies = [{ title: 'Titanic' }, { title: 'Back To The Future' }];
      setMovies(movies);
    }, 1000);
  }, []);

  return (
    <div>
      {movies.length > 0 && (
        <div>
          {movies.map((x) => (
            <div data-testid='movies'>{x.title}</div>
          ))}
        </div>
      )}
    </div>
  );
}

export default App;
Run Code Online (Sandbox Code Playgroud)

这是完整的测试代码...

import { render, screen } from '@testing-library/react';
import App from './App';

test('renders learn react link', () => {
  render(<App />);
  const movieTiles = screen.getAllByTestId('movies');
  expect(movieTiles).toHaveLength(2);
});

Run Code Online (Sandbox Code Playgroud)

这是测试中的错误

在此输入图像描述

sli*_*wp2 5

当您的代码使用计时器(, , , )时,您应该使用假计时器setTimeoutsetIntervalclearTimeoutclearInterval

\n

用于jest.advanceTimersByTime(1000)将时间提前 1000 毫秒。

\n

不要忘记act()辅助函数:

\n
\n

在编写 UI 测试时,渲染、用户事件或数据获取等任务可以被视为与用户界面交互的 \xe2\x80\x9cunits\xe2\x80\x9d 。react-dom/test-utils 提供了一个名为的助手act(),确保在做出任何断言之前与这些 \xe2\x80\x9cunits\xe2\x80\x9d 相关的所有更新都已被处理并应用到 DOM:

\n
\n

由于我们setState提前 1000 毫秒运行将更改组件状态的函数,因此我们必须将此操作 ( jest.advanceTimersByTime(1000)) 包装在act()函数中。

\n

否则,您将收到警告:

\n
\n

警告:测试内应用程序的更新未包含在 act(...) 中。

\n
\n
\n

测试时,导致 React 状态更新的代码应包装到 act(...) 中:

\n
\n

例如

\n

App.jsx

\n
import React, { useEffect, useState } from \'react\';\n\nfunction App() {\n  const [movies, setMovies] = useState([]);\n\n  useEffect(() => {\n    setTimeout(() => {\n      const movies = [{ title: \'Titanic\' }, { title: \'Back To The Future\' }];\n      setMovies(movies);\n    }, 1000 * 10);\n  }, []);\n\n  return (\n    <div>\n      {movies.length > 0 && (\n        <div>\n          {movies.map((x, idx) => (\n            <div key={idx} data-testid="movies">\n              {x.title}\n            </div>\n          ))}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default App;\n
Run Code Online (Sandbox Code Playgroud)\n

App.test.jsx

\n
import { render, screen, act } from \'@testing-library/react\';\nimport React from \'react\';\nimport App from \'./App\';\n\ndescribe(\'68460159\', () => {\n  test(\'renders learn react link\', async () => {\n    jest.useFakeTimers();\n    render(<App />);\n    act(() => {\n      jest.advanceTimersByTime(1000 * 10);\n    });\n    const movieTiles = screen.getAllByTestId(\'movies\');\n    expect(movieTiles).toHaveLength(2);\n    jest.runOnlyPendingTimers();\n    jest.useRealTimers();\n  });\n});\n
Run Code Online (Sandbox Code Playgroud)\n

测试结果:

\n
 PASS  examples/68460159/App.test.jsx (7.878 s)\n  68460159\n    \xe2\x9c\x93 renders learn react link (33 ms)\n\n----------|---------|----------|---------|---------|-------------------\nFile      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s \n----------|---------|----------|---------|---------|-------------------\nAll files |     100 |      100 |     100 |     100 |                   \n App.jsx  |     100 |      100 |     100 |     100 |                   \n----------|---------|----------|---------|---------|-------------------\nTest Suites: 1 passed, 1 total\nTests:       1 passed, 1 total\nSnapshots:   0 total\nTime:        8.678 s, estimated 10 s\n
Run Code Online (Sandbox Code Playgroud)\n