使用Jest测试React-Apollo的MockedProvider遇异步问题,需设置超时?
解决Jest搭配MockedProvider测试时的异步行为问题
嘿,我完全懂你遇到的这个困扰——MockedProvider本身就是异步工作的,它模拟的是Apollo Client发起查询、接收响应的完整异步流程,不会在第一次渲染时就直接返回模拟数据。这也是为什么你直接断言可能总是拿到loading状态的原因,不一定非要设置超时,但得正确等待查询完成才行。
先帮你修正下组件里的语法小问题(避免测试时因为语法报错干扰判断):
const Component = () => ( <Query query={query}> {({ loading, data }) => { if (loading) return 'loading'; if (data) return 'data'; return 'nothing'; }} </Query> );
下面给你几种靠谱的解决方案:
方法1:使用async/await + waitFor(推荐)
如果你的项目里用了@testing-library/react,waitFor可以帮你自动等待组件状态更新到预期值,不用手动处理超时逻辑:
import { waitFor } from '@testing-library/react'; import TestRenderer from 'react-test-renderer'; import { MockedProvider } from '@apollo/client/testing'; import Component from './Component'; it('renders data after query completes', async () => { const mocks = [ { request: { query: yourQuery }, result: { data: { /* 填入你的模拟数据 */ } }, }, ]; const { getByText } = TestRenderer.create( <MockedProvider mocks={mocks} addTypename={false}> <Component /> </MockedProvider> ); // 初始渲染状态是loading expect(getByText('loading')).toBeInTheDocument(); // 等待异步查询完成,直到渲染出data await waitFor(() => { expect(getByText('data')).toBeInTheDocument(); }); });
方法2:利用TestRenderer回调 + setTimeout
如果不用testing-library,也可以用setTimeout给MockedProvider一点时间处理异步流程,配合Jest的done回调:
it('renders data after query completes', (done) => { const renderer = TestRenderer.create( <MockedProvider mocks={myMock} addTypename={false}> <Component /> </MockedProvider> ); // 初始渲染是loading状态 expect(renderer.toJSON()).toMatch('loading'); // 等待React完成状态更新(0毫秒足够触发异步队列) setTimeout(() => { expect(renderer.toJSON()).toMatch('data'); done(); // 告诉Jest测试已完成 }, 0); });
方法3:临时设置Jest超时(应急可用)
如果上面的方法都没生效,可能是你的模拟逻辑有自定义延迟(比如自定义了resolver),这时候可以临时调整Jest的超时时间:
it('renders data after query completes', async () => { jest.setTimeout(1000); // 把超时设为1秒,Jest默认是5000毫秒其实足够 // 剩下的测试逻辑和方法1一致 });
几个关键注意点:
- 记得给
MockedProvider加上addTypename={false},如果你的查询里没有包含__typename字段,不然会匹配不到模拟请求。 - 确保
mocks数组里的request.query和组件中使用的query完全一致,包括变量(如果有传参的话)。 - 如果你用的是旧版
react-apollo而非@apollo/client,MockedProvider的API略有差异,但异步处理逻辑是相通的。
内容的提问来源于stack exchange,提问作者tgk
相关产品推荐
相关产品推荐

