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

在Jest中模拟带withFileTypes的fs.readdirSync遇错误如何解决?

问题描述

我有一个通过fs.readdirSync获取目录文件名的函数:

export const getDirectoryFiles = async (directory) => {
  return fs
  .readdirSync(directory, { withFileTypes: true })
  .filter(dirent => !dirent.isDirectory())
  .map(dirent => dirent.name);
}

尝试用Jest的jest.spyOn模拟该方法时,测试报错:

TypeError: fs.readdirSync(...).filter is not a function

我的测试代码如下:

it('getDirectoryFiles', async () => {
  const { Dirent, constants } = jest.requireActual('fs');

  // Prepare our mock
  const directory = new Dirent('directory', constants.UV_DIRENT_DIR);
  const fsMock = jest.spyOn(fs, 'readdirSync');

  fsMock.mockResolvedValue([directory]);

  // expect.assertions(1);
  const files = await getDirectoryFiles("/dir/stuff");

  // quick test
  expect(files).not.toBeNull;
});

希望解决报错问题,同时模拟返回两个文件名来验证函数的正确性。

解决方案

1. 修复同步方法的模拟方式

fs.readdirSync是同步方法,你用的mockResolvedValue是用来模拟异步Promise返回值的,这会导致readdirSync返回Promise而非数组,自然没有filter方法——这就是报错的核心原因。

把mockResolvedValue替换为mockReturnValue即可解决类型错误。

2. 模拟符合要求的Dirent实例

你需要创建文件类型的Dirent对象(而非目录类型),这样filter逻辑才会保留它们,最终映射出正确的文件名。无需依赖真实的Dirent类,手动模拟必要的方法和属性即可满足测试需求。

完整测试代码

it('getDirectoryFiles should return correct filenames', async () => {
  // 模拟两个文件的Dirent对象
  const mockFile1 = {
    isDirectory: () => false,
    name: 'file1.txt'
  };
  const mockFile2 = {
    isDirectory: () => false,
    name: 'file2.js'
  };
  // 模拟一个目录,验证是否会被过滤
  const mockDir = {
    isDirectory: () => true,
    name: 'subdir'
  };

  const fsMock = jest.spyOn(fs, 'readdirSync');
  // 同步方法用mockReturnValue返回数组
  fsMock.mockReturnValue([mockFile1, mockFile2, mockDir]);

  const files = await getDirectoryFiles("/dir/stuff");

  // 验证结果只包含文件,不包含目录
  expect(files).toEqual(['file1.txt', 'file2.js']);
  // 验证readdirSync被正确调用
  expect(fsMock).toHaveBeenCalledWith("/dir/stuff", { withFileTypes: true });
});

额外说明

  • 你的getDirectoryFiles函数标记了async,但内部用的是同步方法readdirSync,实际上可以去掉async,不过这不会影响测试逻辑。
  • 无需引入真实的Dirent类,模拟isDirectory方法和name属性就足够覆盖函数的过滤、映射逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:27:21