ReactJS/JestJS/Enzyme:如何测试compose中graphql的options函数?
如何测试React-Apollo中graphql高阶组件的options函数
嘿,我懂你遇到的问题了!你现在测试的是未被graphql高阶组件包装的原始<Example>组件,那options函数根本没机会执行,覆盖率当然不会统计到它。下面给你两种靠谱的解决办法,按需选就行:
方法一:直接测试提取出来的options纯函数
这是最简单高效的方式,因为options本质就是个接收props返回配置的纯函数,完全可以单独拎出来测试,不用折腾高阶组件的环境。
首先修改你的Example.js,把options函数单独导出:
import React, { Component } from 'react' import { graphql, compose } from 'react-apollo' import { getPostsQuery } from './graphql/query' // 单独导出options函数,方便测试 export const getPostsOptions = (props) => ({ variables: { articleId: props.articleId } }) export class Example extends Component { render () { const { data } = this.props const { getPosts, loading } = data return ( <div id="article"> { getPosts.map(post => { return (<div>{post.content}</div>) }) } </div> ) } } export default compose( graphql( getPostsQuery, { options: getPostsOptions } // 这里用导出的函数 ) )(Example)
然后在测试文件中直接测试这个函数:
import { getPostsOptions } from './components/Example' describe('getPostsOptions', () => { it('should generate correct variables from props', () => { const testProps = { articleId: 'test-123' } const result = getPostsOptions(testProps) expect(result.variables).toEqual({ articleId: 'test-123' }) }) })
这样一来,那行options: (props) => ({...})的代码就被完全覆盖了,而且测试逻辑简单直接,后期维护也方便。
方法二:测试完整的包装后组件(端到端验证)
如果你想验证整个组件流程(包括graphql高阶组件如何使用options发起请求),那就需要测试默认导出的那个被包装后的组件,同时模拟Apollo的运行环境。
首先安装必要的依赖(如果还没装):
npm install @apollo/client enzyme-adapter-react-16 --save-dev
然后编写测试代码:
import React from 'react' import { mount } from 'enzyme' import { ApolloProvider, ApolloClient, InMemoryCache } from '@apollo/client' import Example from './components/Example' // 导入默认导出的包装后组件 import { getPostsQuery } from './graphql/query' // 创建模拟的Apollo Client const mockClient = new ApolloClient({ cache: new InMemoryCache(), // 这里可以添加mock链路来模拟请求返回,不过我们主要验证options,所以基础配置就行 }) describe('<Example />', () => { it('should execute options function with given props', () => { // 监听client的query方法,验证请求参数 const querySpy = jest.spyOn(mockClient, 'query') // 用mount渲染组件(shallow不会渲染高阶组件内部逻辑) mount( <ApolloProvider client={mockClient}> <Example articleId="test-456" /> {/* 传递触发options的props */} </ApolloProvider> ) // 验证query调用时使用了options生成的正确变量 expect(querySpy).toHaveBeenCalledWith(expect.objectContaining({ query: getPostsQuery, variables: { articleId: 'test-456' } })) }) it('should render #article element correctly', () => { const wrapper = mount( <ApolloProvider client={mockClient}> <Example articleId="test-789" data={{ getPosts: [{ content: 'test post' }], loading: false }} /> </ApolloProvider> ) expect(wrapper.find('#article')).toHaveLength(1) expect(wrapper.find('#article div').text()).toBe('test post') }) })
这种方式能验证整个组件的工作流程,确保options函数确实在组件接收props时被正确调用,生成了预期的请求变量。
两种方法各有优劣:第一种适合单独验证options的逻辑,快速覆盖代码;第二种适合做集成测试,确保组件整体行为符合预期。你可以根据自己的测试需求选择~
内容的提问来源于stack exchange,提问作者user3142695
相关产品推荐
相关产品推荐

