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

如何用Jest测试函数内部的函数调用?遇ESM适配问题

Jest测试函数调用问题解决方案

问题背景

我已经用给出的第一个方案解决了问题。之前在Jest中缺少Babel配置,我使用了Jest文档中提到的实验性ES6+设置,要求移除转换配置、添加测试命令node --experimental-vm-modules node_modules/jest/bin/jest.js等,但我不太清楚这些设置的作用,本以为是解决这类问题的,但显然不是。

我查阅了很多相关帖子并尝试了多种方案,但都无效。请问如何用Jest测试init函数内部是否调用了calling函数?

我的代码

calling.js

const calling = () => {
  return 'calling';
};

export default calling;

init.js

import calling from './calling';

export const init = () => {
  calling();
};

test.spec.js

import { jest } from '@jest/globals';
import init from './init.js';
import calling from './calling.js';

test('init calls calling', () => {
  // 这里该怎么写?
});

package.json

{
  "name": "testing",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
  },
  "type": "module",
  "jest": {
    "transform": {},
    "roots": [
      "<rootDir>"
    ],
    "modulePaths": [
      "<rootDir>"
    ],
    "moduleDirectories": [
      "node_modules"
    ]
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/jest": "^28.1.8",
    "jest": "^28.1.3"
  }
}

当前遇到的问题

现在基于上述方案勉强能运行,但有问题!我必须做更复杂的配置才能运行,不知道原因。而且我只能使用命名导出,因为默认导出无法生效,我也不知道如何解决这个问题。

当前测试代码:

import { jest } from '@jest/globals';

const mock = jest.fn();

jest.unstable_mockModule('./calling.js', () => ({
  calling: mock,
}));

const { calling } = await import('./calling.js');
const { init } = await import('./init.js');

test('test', async () => {
  init();
  expect(calling).toHaveBeenCalled();
});

解决方案

问题出在你对默认导出的mock方式不对。因为calling.js用的是默认导出,所以在jest.unstable_mockModule中需要返回default字段,而不是命名导出的calling。修改后的测试代码如下:

import { jest } from '@jest/globals';

const mockCalling = jest.fn();

// 针对默认导出进行mock
jest.unstable_mockModule('./calling.js', () => ({
  default: mockCalling,
}));

// 正确导入默认导出的mock函数
const calling = (await import('./calling.js')).default;
const { init } = await import('./init.js');

test('init calls calling', () => {
  init();
  expect(mockCalling).toHaveBeenCalled();
});

说明

  1. 因为你的calling是默认导出,所以mock模块时必须指定default属性,这样init.js中导入的默认导出才会被替换成mock函数。
  2. 导入时要通过(await import('./calling.js')).default获取默认导出的mock函数,而不是解构calling。
  3. 直接断言mock函数mockCalling是否被调用即可,这样就能正确验证init内部是否执行了calling函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 01:48:38