使用Enzyme测试调用react-apollo readQuery的React组件
嘿,我来帮你搞定这个Enzyme测试React Apollo组件的问题!核心就是得给组件提供一个模拟的Apollo Client,让它在测试环境里能正常调用readQuery,不会因为找不到client而报错。下面给你两种实用的解决方案:
解决Enzyme测试React Apollo组件时未模拟Apollo Client的报错问题
方案一:用Apollo官方的MockedProvider(推荐)
这是Apollo官方推荐的测试方式,它能模拟整个Apollo Client的上下文环境,让组件可以像在真实环境里一样执行查询操作,还能自定义返回的数据。
具体步骤:
- 从
@apollo/client/testing里导入MockedProvider - 定义你需要模拟的查询,以及对应的返回数据
- 用
MockedProvider把要测试的组件包裹起来,传入模拟的查询配置
示例代码:
import { MockedProvider } from '@apollo/client/testing'; import { mount } from 'enzyme'; import YourComponent from './YourComponent'; import { YOUR_TARGET_QUERY } from './your-queries-file'; // 替换成你实际的查询 // 配置模拟的查询和返回数据 const queryMocks = [ { request: { query: YOUR_TARGET_QUERY, variables: { /* 如果你的查询需要变量,这里填对应的值 */ } }, result: { data: { /* 这里填组件通过readQuery期望拿到的具体数据 */ } } } ]; describe('YourComponent测试', () => { it('componentDidMount后能正常渲染', async () => { const wrapper = mount( <MockedProvider mocks={queryMocks} addTypename={false}> <YourComponent /> </MockedProvider> ); // 因为Apollo查询是异步的,需要等模拟查询完成再更新组件 await new Promise(resolve => setTimeout(resolve, 0)); wrapper.update(); // 这里写你的断言逻辑,比如检查组件是否渲染了预期内容 expect(wrapper.find('.your-target-element').text()).toBe('你期望的文本'); }); });
注:addTypename={false}是为了避免Apollo自动添加的__typename字段导致查询匹配失败,如果你在真实代码里用到了这个字段,可以去掉这个配置。
方案二:手动模拟Apollo Client并通过上下文传递
如果你不想用官方的MockedProvider,也可以自己手动创建一个模拟的Apollo Client实例,然后通过Apollo的上下文传递给组件。这种方式更灵活,适合需要精准控制client方法调用的场景。
具体步骤:
- 导入
ApolloProvider - 用
jest.fn()创建一个带有readQuery方法的模拟client,自定义它的返回值 - 用
ApolloProvider包裹组件,把模拟的client传进去
示例代码:
import { ApolloProvider } from '@apollo/client'; import { mount } from 'enzyme'; import YourComponent from './YourComponent'; import { YOUR_TARGET_QUERY } from './your-queries-file'; // 手动模拟Apollo Client实例 const mockApolloClient = { readQuery: jest.fn(() => ({ // 返回组件期望的查询结果 user: { id: 1, name: 'Mock User' } })) }; describe('YourComponent测试', () => { it('componentDidMount时会调用readQuery', () => { const wrapper = mount( <ApolloProvider client={mockApolloClient}> <YourComponent /> </ApolloProvider> ); // 断言readQuery是否被调用 expect(mockApolloClient.readQuery).toHaveBeenCalled(); // 还可以检查调用的参数是否正确 expect(mockApolloClient.readQuery).toHaveBeenCalledWith({ query: YOUR_TARGET_QUERY, variables: { /* 如果有变量,这里填对应的值 */ } }); }); });
额外提示
- 不管你的组件是用
useApolloClient钩子获取client,还是用withApollo高阶组件注入client,上面两种方案都能正常生效 - 处理异步操作时,一定要记得等待组件更新后再做断言,不然可能会拿到未更新的DOM
- 如果你用的是老版本的
react-apollo(不是@apollo/client),只需要把导入路径换成react-apollo/testing即可
内容的提问来源于stack exchange,提问作者Cristian Rojas
相关产品推荐
相关产品推荐

