【问题标题】:React Testing Library does not find elements using getAllByTestId after initial renderReact 测试库在初始渲染后未使用 getAllByTestId 找到元素
【发布时间】:2021-09-28 06:40:19
【问题描述】:

我有一个非常简单的组件,我试图在其中模拟 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;

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

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);
});

这是测试的错误

【问题讨论】:

    标签: javascript reactjs testing jestjs react-testing-library


    【解决方案1】:

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

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

    别忘了act() 辅助函数:

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

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

    否则会收到警告:

    警告:测试中对 App 的更新未包含在 act(...) 中。

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

    例如

    App.jsx:

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

    App.test.jsx:

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

    测试结果:

     PASS  examples/68460159/App.test.jsx (7.878 s)
      68460159
        ✓ renders learn react link (33 ms)
    
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |     100 |     100 |                   
     App.jsx  |     100 |      100 |     100 |     100 |                   
    ----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        8.678 s, estimated 10 s
    

    【讨论】:

    • 太棒了,所以如果我进行 API 调用,这会不会一样?我只是使用上面的计时器来模拟,但是当我使用 API 调用时遇到了同样的问题,它有轻微的延迟
    • @user3284707 API调用不同,需要使用msw搭建一个mock API server,并使用await waitFor()等待组件状态变化。见testing-library.com/docs/react-testing-library/example-intro
    • 啊,好的,谢谢,所以你不能使用内部有真正 API 调用的组件,对吗?我对如何使用一个使用真实 API 调用的真实组件并将其替换为用于测试目的的模拟组件感到有些困惑?
    猜你喜欢
    • 2019-07-08
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多