如何使用 react-testing-library 和 jest 测试在 useEffect 中获取数据并将其存储在状态中的组件?
2021-11-23
3345
我对 react-testing-library 和一般测试还不太熟悉。我想测试一个组件,该组件从 useEffect 钩子中的 API 中获取数据。然后将其存储在本地状态中。它使用 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) => {
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(() => server.listen());
afterAll(() => server.close());
beforeEach(() => server.restoreHandlers());
//console.log("mocking axios", axios)
describe('OnePiece', () => {
test('fetches the data from the API and correctly renders it', async () => {
//Here's probably where i fail. Please someone tell me the right way :)
await render(<OnePiece />)
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(() => {
let isApiSubscribed = true;
const getOpData = async () => {
const getCrews = await axios.get('http address');
if (isApiSubscribed) {
let data = getCrews.data;
data = data[crew];
// console.log("data", data);
setTotalData(data);
}
}
getOpData();
return () => {
isApiSubscribed=false;
}
}, [crew])
.........
//in the return part
<ProductsWrapper>
{totalData.map((product, index) =>
<ProductCard key={index} name={product.name} price={product.price} imageUrl={product.image} />
)}
</ProductsWrapper>
1个回答
正如我所料,问题出在异步数据获取上。目前 setTimeOut 对我来说已经足够了,但如果以后有人看到这个问题,你可以查找 react-testing-library 的 waitFor 方法。 这是修复的部分:
describe('OnePiece', () => {
test('fetches the data from the API and correctly renders it', async () => {
render(<OnePiece />)
setTimeout(async () => {
const items = await screen.findAllByAltText('product-image');
expect(items).toHaveLength(2);
}, 4000)
//screen.debug()
})
})
dumblessar
2021-11-23