You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue+Vitest+MSW:无法在组合式函数中Mock并测试GraphQL查询结果

问题分析

你当前的测试存在两个核心问题:

  1. Mock方案冲突:测试中同时使用了mock-apollo-client和MSW。provideApolloClient提供的Mock Apollo客户端会直接拦截查询,不会发起真实网络请求,导致MSW无法捕获到请求,自然无法返回Mock数据。
  2. 异步未等待: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 11:12:03