[英]How to mock fetch when testing a React app?
我想测试一个使用全局fetch
方法的小型 React web 应用程序。
我试图以这种方式模拟fetch
:
global.fetch = jest.spyOn(global, 'fetch').mockImplementation(endpoint =>
Promise.resolve({
json: () => Promise.resolve(mockResponse)
})
);
...但是模拟似乎被忽略了,而内置的fetch
似乎被使用: Error: connect ECONNREFUSED 127.0.0.1:80...
看起来像对内置fetch
的失败调用。
然后我尝试使用jest.fn
而不是jest.spyOn
:
global.fetch = jest.fn(endpoint =>
Promise.resolve({
json: () => Promise.resolve(mockResponse)
})
);
...并且惊讶地看到一个不同的错误。 现在模拟似乎被考虑在内,但同时无法正常工作:
TypeError: Cannot read property 'then' of undefined
8 | this.updateTypes = this.props.updateTypes;
9 | this.updateTimeline = this.props.updateTimeline;
> 10 | fetch('/timeline/tags')
| ^
11 | .then(res => res.json())
12 | .then(tags => tags.map(tag => <option value={tag} key={tag} />))
13 | .then(options => options.sort((a, b) => a.key.localeCompare(b.key)))
老实说,我发现 Jest 和 React 测试库的文档有点混乱。 我正在做的事情可能有什么问题?
我正在尝试测试的 React 组件称为“App”,是使用 Create React App 生成的,并已更改为包含对fetch
的调用。 我很乐意为这个组件提供代码,但我相信问题在于测试。
在我的App.test.js
文件的开头,我import React from 'react';
, 然后import { render, fireEvent, waitFor, screen } from '@testing-library/react';
, 最后import App from './App';
. 随后,我尝试以我描述的一种方式模拟fetch
,然后声明以下测试:
test('renders a list of items, upon request', async () => {
const app = render(<App />);
fireEvent.click(screen.getByText('Update'));
await waitFor(() => screen.getByRole('list'));
expect(screen.getByRole('list')).toBeInTheDocument();
expect(screen.getByRole('list')).toHaveClass('Timeline');
});
最后,我用global.fetch.mockRestore();
结束我的测试文件。 .
存在ECONNREFUSED
错误而不是fetch is not defined
意味着fetch
已被填充。 它不是 JSDOM 的一部分,也不是由 Jest 本身填充的,而是特定于当前设置的。 在这种情况下,polyfill 由 create-react-app 提供。
最好使用 jest.spyOn 模拟现有的全局jest.spyOn
而不是将它们分配为global
属性,这允许 Jest 进行清理。 像global.fetch = jest.spyOn(global, 'fetch')
这样的事情永远不应该做,因为这会阻止fetch
被恢复。 这可以解释TypeError: Cannot read property 'then' of undefined
error for 看似正确模拟的 function。
模拟全局变量的正确且安全的方法是在每次测试之前模拟它们并在每次测试后恢复:
beforeEach(() => {
jest.spyOn(global, 'fetch').mockResolvedValue({
json: jest.fn().mockResolvedValue(mockResponse)
})
});
afterEach(() => {
jest.restoreAllMocks();
});
为了使模拟正常工作,不应对global.fetch
进行其他修改。
恢复模拟和间谍的一种更好的方法是使用配置选项而不是jest.restoreAllMocks
因为不这样做可能会导致意外的测试交叉污染,这是不可取的。
TypeError: Cannot read property 'then' of undefined
error 出现的另一个原因是 Jest 错误地指向fetch
行,而错误实际上是指另一行。 如果源映射不能正常工作,就会发生这种情况。 如果fetch
被正确地模拟并且在同一个组件中还有其他的, then
这是对错误的合理解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.