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

Node18+TypeScript环境下Nock无法拦截Fetch请求的解决方法

Nock无法拦截Node.js 18原生fetch请求,真实接口被调用

问题背景

我在Node.js 18的TypeScript项目中使用Nock测试一个通过原生fetch调用接口的MagicClient类,但Nock完全失效,真实接口被调用,返回真实响应而非Mock数据。

客户端代码(MagicClient.ts)

type Config = {
    baseUrl: string;
};

export default class MagicClient {
    // eslint-disable-next-line no-useless-constructor
    constructor(private readonly config: Config) {}

    public async doMagic(): Promise<Object> {
        const response = await fetch(`${this.config.baseUrl}/do-magic`, {
            method: 'POST',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ magic: true }),
        });

        return JSON.parse(await response.text());
    }
}

测试代码(MagicClient.test.ts)

import nock from 'nock';

import MagicClient from '../../../src/MagicClient';

describe(MagicClient.name, () => {
    const client = new MagicClient({
        baseUrl: process.env.MAGIC_BASE_URL, 
    });

    beforeEach(() => {
        jest.resetAllMocks();

        nock.cleanAll();
        nock.disableNetConnect();
        nock.enableNetConnect('127.0.0.1');
    });

    afterEach(() => {
        expect(nock.isDone()).toBeTruthy();
    });

    const mockedResponse = {
         success: true,
         magic: 'abc',
    };
    it('calls do magic', () => {
        nock(process.env.MAGIC_BASE_URL)
            .post('/do-magic', { magic: true })
            .reply(200, mockedResponse);

        expect(
            client.doMagic(),
        ).toEqual(mockedResponse);
    });
});

环境信息

node v18.16.0
"jest": "^29.2.0",
"nock": "^13.4.0",

问题原因

  1. Nock默认不支持Node.js 18原生fetch:Node.js 18的fetch基于undici库实现,而Nock默认只拦截传统http/https模块的请求,无法直接拦截undici驱动的fetch调用。
  2. 测试未正确处理异步逻辑:doMagic是异步函数,测试中未使用await等待请求完成,导致expect在请求发送前就执行,Nock的拦截规则还未生效,真实请求已发出。
  3. 主机名配置可能不匹配:如果process.env.MAGIC_BASE_URL包含协议(如https://),Nock需要完整匹配该地址;若传递格式错误,拦截规则会不匹配,请求会绕过Nock。

解决方案

1. 启用Nock对原生fetch的支持

安装Nock的fetch适配包:

npm install @nock/fetch --save-dev

在测试文件顶部导入该包,替换原生fetch:

import '@nock/fetch'; // 放在nock导入之前
import nock from 'nock';

也可以在Jest全局配置文件(如jest.setup.js)中导入,避免每个测试文件重复配置。

2. 修复测试的异步处理

将测试函数改为异步函数,并在expect前添加await,确保等待请求完成后再断言:

it('calls do magic', async () => { // 添加async关键字
    nock(process.env.MAGIC_BASE_URL)
        .post('/do-magic', { magic: true })
        .reply(200, mockedResponse);

    const result = await client.doMagic(); // 添加await等待请求完成
    expect(result).toEqual(mockedResponse);
});

3. 验证主机名配置

确保nock的第一个参数与baseUrl完全匹配(包括协议)。可通过URL对象提取标准格式的主机地址:

const baseUrl = new URL(process.env.MAGIC_BASE_URL);
nock(baseUrl.origin) // 使用origin确保包含协议和主机名
    .post('/do-magic', { magic: true })
    .reply(200, mockedResponse);

4. 强化网络拦截规则

在beforeEach中严格禁用外部网络,避免请求绕过Nock:

beforeEach(() => {
    jest.resetAllMocks();
    nock.cleanAll();
    nock.disableNetConnect();
    // 仅允许本地回环地址的请求
    nock.enableNetConnect('127.0.0.1', 'localhost');
});

修改后的完整测试代码

import '@nock/fetch';
import nock from 'nock';

import MagicClient from '../../../src/MagicClient';

describe(MagicClient.name, () => {
    const client = new MagicClient({
        baseUrl: process.env.MAGIC_BASE_URL, 
    });

    beforeEach(() => {
        jest.resetAllMocks();
        nock.cleanAll();
        nock.disableNetConnect();
        nock.enableNetConnect('127.0.0.1', 'localhost');
    });

    afterEach(() => {
        expect(nock.isDone()).toBeTruthy();
    });

    const mockedResponse = {
         success: true,
         magic: 'abc',
    };

    it('calls do magic', async () => {
        const baseUrl = new URL(process.env.MAGIC_BASE_URL);
        nock(baseUrl.origin)
            .post('/do-magic', { magic: true })
            .reply(200, mockedResponse);

        const result = await client.doMagic();
        expect(result).toEqual(mockedResponse);
    });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:50:46