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

如何用Jest和React Testing Library测试含GraphQL请求的Node.js函数并解决fetch问题

解决方案

1. 解决 ReferenceError: fetch is not defined 问题

Node.js 环境本身不支持浏览器的 fetch API,你有两种解决方式:

方法一:引入 polyfill

安装 whatwg-fetch:

npm install whatwg-fetch --save-dev

在测试文件顶部或 Jest 全局配置文件中引入:

import 'whatwg-fetch';

方法二:直接 mock fetch(单元测试推荐)

在测试文件中手动 mock 全局 fetch,无需额外依赖:

global.fetch = jest.fn();

2. getData 函数的单元测试

通过 mock fetch 模拟 GraphQL 请求的成功、失败场景,专注测试函数逻辑:

import getData from './getData';
import GET_DATA from './getData.gql';

// 全局 mock fetch
global.fetch = jest.fn();

describe('getData', () => {
  const mockTargetUrl = '/foo/test';
  const mockSuccessResponse = {
    data: {
      page: {
        content: { type: 'MyPage', id: 'e523f6f6-6e73-4bb0-8737-95b63e1f9e6c' }
      }
    }
  };

  beforeEach(() => {
    jest.clearAllMocks(); // 清除测试间的 mock 调用记录
    process.env.ENDPOINT = 'https://mock-endpoint.com/graphql';
  });

  it('返回正确的页面数据当请求成功时', async () => {
    // 模拟 fetch 成功响应
    (fetch as jest.Mock).mockResolvedValue({
      ok: true,
      json: jest.fn().mockResolvedValue(mockSuccessResponse)
    });

    const result = await getData(mockTargetUrl);
    // 验证 fetch 调用参数是否正确
    expect(fetch).toHaveBeenCalledWith(process.env.ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        query: GET_DATA,
        variables: { targetUrl: mockTargetUrl }
      })
    });
    expect(result).toEqual(mockSuccessResponse.data.page);
  });

  it('抛出错误当响应状态异常时', async () => {
    (fetch as jest.Mock).mockResolvedValue({ ok: false });
    await expect(getData(mockTargetUrl)).rejects.toThrow('Unable to parse json response');
  });

  it('抛出错误当 GraphQL 返回错误信息时', async () => {
    (fetch as jest.Mock).mockResolvedValue({
      ok: true,
      json: jest.fn().mockResolvedValue({ errors: ['请求失败'] })
    });
    await expect(getData(mockTargetUrl)).rejects.toThrow('Something went wrong');
  });
});

3. getRedirectUrl 函数的单元测试

通过 jest.mock 完全隔离 getData 依赖,只测试重定向逻辑:

import getRedirectUrl from './getRedirectUrl';
import getData from './getData';

// mock getData 模块
jest.mock('./getData');

describe('getRedirectUrl', () => {
  const mockValidFooUrl = '/foo/path/6486867645846';
  const mockNonFooUrl = '/bar/path';
  const mockMyPageData = {
    content: { type: 'MyPage', id: 'e523f6f6-6e73-4bb0-8737-95b63e1f9e6c' }
  };
  const mockOtherPageData = { content: { type: 'OtherPage', id: '123' } };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('生成正确的重定向URL当路径包含/foo/且内容为MyPage时', async () => {
    (getData as jest.Mock).mockResolvedValue(mockMyPageData);

    const result = await getRedirectUrl(mockValidFooUrl);
    expect(getData).toHaveBeenCalledWith(mockValidFooUrl);
    expect(result).toBe('/my-page/?id=e523f6f6-6e73-4bb0-8737-95b63e1f9e6c');
  });

  it('返回null当路径包含/foo/但内容不是MyPage时', async () => {
    (getData as jest.Mock).mockResolvedValue(mockOtherPageData);
    const result = await getRedirectUrl(mockValidFooUrl);
    expect(result).toBeNull();
  });

  it('返回null当路径不包含/foo/时', async () => {
    const result = await getRedirectUrl(mockNonFooUrl);
    expect(getData).not.toHaveBeenCalled();
    expect(result).toBeNull();
  });
});

核心注意事项

  • 单元测试要隔离依赖:测试getRedirectUrl时不要触发实际网络请求,通过 mock 切断依赖链。
  • 异步测试必须用async/await:确保 Jest 等待异步操作完成,避免断言提前执行。
  • 清理 mock 状态:每次测试前用jest.clearAllMocks()清除调用记录,防止测试间互相干扰。

内容的提问来源于stack exchange,提问作者meez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:47:15