使用React Testing Library的Mocked Apollo Provider未返回数据问题
Apollo Client + React Testing Library 测试问题排查与解决
问题场景
基于Apollo Client的React组件中,使用useComponentRespQuery时配置了variables和skip参数,用React Testing Library结合MockedProvider测试时,mock数据无法正常返回;只有注释掉这些配置参数,Apollo才能返回正确的mock值。
组件核心代码:
const ComponentToTest = () => { // ... const { data, loading } = useComponentRespQuery({ variables: { id: idValue }, skip: !idValue }); if (loading) { return <>Loading</>; } // ... }
测试核心代码:
const componentRender = (mockGraphQLData: any, initialEntry: string = "") => render( <MemoryRouter initialEntries={[initialEntry]}> <MockedProvider mocks={[ mockGraphQLData ]} addTypename={false}> <ComponentToTest /> </MockedProvider> </MemoryRouter> ); describe("ComponentToTest", () => { it("should render a component to test", async() => { componentRender(zoneMock); const placeHolderValues = await screen.findByText(/Bla/i); expect(placeHolderValues).toBeInTheDocument(); }); // ... }
GraphQL Query定义:
query GetResp($id: ID!) { resp(id: $id) { id name description controls { id name } } }
现有Mock数据:
export const componentRespMock = { request: { query: componentRespDocument }, result: { data: { resp: { id: "ID", name: "NAME", description: "DESCRIPTION", controls: [ { id: "CTRL_2", name: "Second control" } ] } } } };
解决方案
1. 确保Mock请求与组件请求的参数完全匹配
Apollo的MockedProvider会严格匹配Query和Variables,如果Mock的request没有包含variables,而组件请求时带了variables,则无法匹配到Mock数据,导致请求无响应。
修改Mock数据,添加与组件请求一致的variables:
export const componentRespMock = { request: { query: componentRespDocument, variables: { id: "ID" } // 需与组件中idValue的测试值完全一致 }, result: { data: { resp: { id: "ID", name: "NAME", description: "DESCRIPTION", controls: [ { id: "CTRL_2", name: "Second control" } ] } } } };
2. 保证测试时skip条件为false
组件中skip: !idValue,如果测试时idValue为空,Query会被跳过,MockedProvider不会收到请求,自然无法返回Mock数据。
确保测试时组件能获取到有效的idValue,比如通过路由传递:
it("should render a component to test", async() => { // 传入包含id的路由路径,确保组件能获取到idValue为"ID" componentRender(componentRespMock, "/your-component-path/ID"); const placeHolderValues = await screen.findByText(/NAME/i); expect(placeHolderValues).toBeInTheDocument(); });
3. 验证异步流程的完整性
虽然findByText是异步查询,但可以额外等待Loading状态结束,确保Query请求已完成:
it("should render a component to test", async() => { componentRender(componentRespMock, "/your-component-path/ID"); // 等待Loading消失,确认Query请求完成 await waitFor(() => expect(screen.queryByText("Loading")).not.toBeInTheDocument()); const placeHolderValues = await screen.findByText(/NAME/i); expect(placeHolderValues).toBeInTheDocument(); });
4. 排查是否存在未Mock的其他Query
如果组件中还有其他未被Mock的GraphQL Query,MockedProvider会抛出错误,导致组件无法正常渲染。可以在测试中添加错误检查:
it("should render a component to test", async() => { componentRender(componentRespMock, "/your-component-path/ID"); // 确保没有GraphQL错误提示 expect(await screen.queryByText(/Error/i)).not.toBeInTheDocument(); const placeHolderValues = await screen.findByText(/NAME/i); expect(placeHolderValues).toBeInTheDocument(); });
内容的提问来源于stack exchange,提问作者Jean-Baptiste
相关产品推荐
相关产品推荐

