Vue+Vitest+MSW:无法在组合式函数中Mock并测试GraphQL查询结果
问题分析
你当前的测试存在两个核心问题:
- Mock方案冲突:测试中同时使用了
mock-apollo-client和MSW。provideApolloClient提供的Mock Apollo客户端会直接拦截查询,不会发起真实网络请求,导致MSW无法捕获到请求,自然无法返回Mock数据。 - 异步未等待:
useQuery是异步执行的,对应的计算属性countries初始值为undefined,测试中直接断言会因为时机过早而失败。
解决方案
1. 移除冲突依赖,统一使用MSW
删除测试中mock-apollo-client相关代码,让Apollo客户端发起真实请求(会被MSW拦截):
修改后的useFetchCountries.spec.ts:
import { afterEach, beforeEach, describe, expect, it, waitFor } from "vitest"; import useFetchCountries from "./useFetchCountries"; import { provideApolloClient } from "@vue/apollo-composable"; // 导入项目中实际的Apollo客户端实例 import apolloClient from "../apollo/client"; describe.only("composable - useFetchCountries", () => { beforeEach(() => { // 提供真实Apollo客户端,请求将被MSW拦截 provideApolloClient(apolloClient); }); it("retrieves a list of countries", async () => { const { countries } = useFetchCountries(); // 等待异步查询完成,计算属性更新 await waitFor(() => { expect(countries.value).toBeDefined(); }); // 断言Mock数据的结构与内容 expect(countries.value).toEqual([ { code: "AD", name: "Andorra", currency: "EUR" }, { code: "AT", name: "Austria", currency: "EUR" }, { code: "AX", name: "Åland", currency: "EUR" }, { code: "BE", name: "Belgium", currency: "EUR" }, { code: "BL", name: "Saint Barthélemy", currency: "EUR" }, ]); }); });
2. 确保MSW在测试环境正确初始化
确认setup-file.ts配置无误:
import { setupServer } from 'msw/node' import { handlers } from './mocks/handlers' const server = setupServer(...handlers) beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close())
同时vitest.config.ts需正确引入该文件:
export default defineConfig({ test: { setupFiles: ['./src/setup-file.ts'], // 其他测试配置 }, })
3. 可选:改用mock-apollo-client(不依赖MSW)
若不想用MSW,可直接Mock Apollo查询逻辑:
修改测试代码:
import { provideApolloClient } from "@vue/apollo-composable"; import { createMockClient } from "mock-apollo-client"; import { afterEach, beforeEach, describe, expect, it, waitFor } from "vitest"; import useFetchCountries from "./useFetchCountries"; import { GET_COUNTRIES } from "./useFetchCountries"; describe.only("composable - useFetchCountries", () => { let mockApolloClient; beforeEach(() => { mockApolloClient = createMockClient(); provideApolloClient(mockApolloClient); }); it("retrieves a list of countries", async () => { const dummyCountries = [ { code: "AD", name: "Andorra", currency: "EUR" }, { code: "AT", name: "Austria", currency: "EUR" }, { code: "AX", name: "Åland", currency: "EUR" }, { code: "BE", name: "Belgium", currency: "EUR" }, { code: "BL", name: "Saint Barthélemy", currency: "EUR" }, ]; // 为目标查询设置Mock返回值 mockApolloClient.setRequestHandler( GET_COUNTRIES, () => Promise.resolve({ data: { countries: dummyCountries } }) ); const { countries } = useFetchCountries(); await waitFor(() => { expect(countries.value).toEqual(dummyCountries); }); }); });
关键说明
- MSW适合模拟网络层请求,更贴近真实用户场景;
mock-apollo-client直接Mock客户端查询逻辑,测试速度更快,可根据需求选择。 - 测试Vue异步响应式数据时,必须用
waitFor或nextTick等待响应式更新完成后再断言。
内容的提问来源于stack exchange,提问作者dunct
相关产品推荐
相关产品推荐

