Как протестировать компонент, который извлекает данные в useEffect и сохраняет их в состоянии с помощью библиотеки реактивного тестирования и jest?

#reactjs #unit-testing #jestjs #react-testing-library

Вопрос:

Я довольно новичок в библиотеке реактивного тестирования и в целом в тестировании. Я хочу протестировать компонент, который извлекает данные из API в useEffect hook. Затем он сохраняет его в локальном состоянии. Он отображает эти данные массива с помощью array.map, но я получаю Error: Uncaught [TypeError: Cannot read properties of undefined (reading 'map')] ошибку. Я, вероятно, ошибаюсь в своем наборе тестов, я много исследовал, но не смог это исправить.

 import React from 'react';  import { render, screen } from '@testing-library/react';  import '@testing-library/jest-dom'  import { rest } from 'msw';  import { setupServer } from 'msw/node';   import { OnePiece } from '.';   const server = setupServer(rest.get('server http address', (req, res, ctx) =gt; {  const totalData = [  { name: "doffy", price: 100, image: "image url" },  { name: "lamingo", price: 500, image: "image url" }  ];  return res(  ctx.status(200),  ctx.json({  data: { crew: totalData }  })  )  }))  beforeAll(() =gt; server.listen());  afterAll(() =gt; server.close());  beforeEach(() =gt; server.restoreHandlers());   //console.log("mocking axios", axios)  describe('OnePiece', () =gt; {    test('fetches the data from the API and correctly renders it', async () =gt; {  //Here's probably where i fail. Please someone tell me the right way :)   await render(lt;OnePiece /gt;)  const items = await screen.findAllByAltText('product-image');  expect(items).toHaveLength(2);  // screen.debug()  })  })  

А ниже приведены части кода useEffect и totalData.map в компоненте:

 const [totalData, setTotalData] = useState([]); const [crew, setCrew] = useState('straw-hat-pirates');   useEffect(() =gt; {  let isApiSubscribed = true;  const getOpData = async () =gt; {  const getCrews = await axios.get('http address');  if (isApiSubscribed) {  let data = getCrews.data;  data = data[crew];  // console.log("data", data);  setTotalData(data);  }  }  getOpData();  return () =gt; {  isApiSubscribed=false;  } }, [crew]) .........  //in the return part  lt;ProductsWrappergt;  {totalData.map((product, index) =gt;  lt;ProductCard key={index} name={product.name} price={product.price} imageUrl={product.image} /gt;  )}  lt;/ProductsWrappergt;  

Ответ №1:

Как я и предсказывал, проблема заключалась в асинхронной выборке данных. В настоящее время setTimeout для меня более чем достаточно, но если кто-то увидит это в будущем, вы можете поискать метод waitFor библиотеки тестирования реакции. Вот фиксированная часть:

 describe('OnePiece', () =gt; {  test('fetches the data from the API and correctly renders it', async () =gt; {  render(lt;OnePiece /gt;)  setTimeout(async () =gt; {  const items = await screen.findAllByAltText('product-image');  expect(items).toHaveLength(2);  }, 4000)  //screen.debug()  })  })