Jest - 模拟 FS 模块和调用配置模块时出错

Jest - getting error when mocking FS modules and calling config module

我正在用 Jest 编写单元测试,试图测试使用 FS 的模块。

模块文件:

import fs from 'fs';
import logger from './logger.utils';

export const getNumberOfFiles = async (targetDir: string): Promise<number> => {
  // get number of folders
  logger.info(`getNumberOfFiles from ${targetDir}/${fileName}`);
  const numberOfFiles = await fs.readdirSync(targetDir);
  return numberOfFiles.length;
};

测试文件

import fs from 'fs';
import { getNumberOfFiles } from '../../src/utils/fs.utils';

jest.mock('fs');

describe('fs.utils', () => {
  describe('getNumberOfFiles', () => {
    it('Should return number', async () => {
      fs.readdirSync = jest.fn();
      const readdirSyncMock = fs.readdirSync = jest.fn();
      readdirSyncMock.mockResolvedValue([1, 2, 3]);

      const result = await getNumberOfFiles('targetDir');
      expect(result).toEqual(3);
      expect(readdirSyncMock.mock.calls.length).toEqual(1);
    });
  });
});

当我运行测试文件时,出现以下错误:

配置文件..../config/runtime.json 无法读取。错误代码是:未定义。错误消息是:无法读取未定义的 属性 'replace'

  1 | const cheggLogger = require('@chegg/logger');
  2 | import loggingContext from './loggingContext';
> 3 | import config from 'config';
    | ^
  4 | import os from 'os';
  5 | import constants from '../../config/constants';
  6 | 

  at Config.Object.<anonymous>.util.parseFile (node_modules/config/lib/config.js:789:13)
  at Config.Object.<anonymous>.util.loadFileConfigs (node_modules/config/lib/config.js:666:26)
  at new Config (node_modules/config/lib/config.js:116:27)
  at Object.<anonymous> (node_modules/config/lib/config.js:1459:31)
  at Object.<anonymous> (src/utils/logger.utils.ts:3:1)

logger.utils.ts

的内容
const internalLogger = require('internalLogger');
import loggingContext from './loggingContext';
import config from 'config';
import os from 'os';
import constants from '../../config/constants';

const logger = internalLogger.createLogger({
  level: config.get(constants.LOG_LEVEL)
});

export default logger;

我假设配置正在使用 FS,一旦我模拟模块,它就会失败。 我该如何解决这个问题?请指教

我猜问题出在 config 也使用了 fs api 但你现在模拟了整个模块 fs 这使得所有方法都应该被模拟使用前。

但是我有一个想法,可以使用 jest.doMock,您可以为每个测试提供一个工厂,并且只模拟我们需要的方法。这是一个想法草案:

describe('fs.utils', () => {
  describe('getNumberOfFiles', () => {
    it('Should return number', async () => {

      jest.doMock('fs', () => ({
        // Keep other methods still working so `config` or others can use
        // so make sure we don't break anything
        ...jest.requireActual('fs'),
        readdirSync: jest.fn(pathUrl => {
          // Mock for our test path since `config` also uses this method :(
          return pathUrl === 'targetDir' ? Promise.resolve([1, 2, 3]) : jest.requireActual('fs').readdirSync(pathUrl)
        })
      }));
      
      // One of the thing we should change is to switch `require` here
      // to make sure the mock is happened before we actually require the code
      // we can also use `import` here but requires us do a bit more thing
      // so I keep thing simple by using `require`
      const {getNumberOfFiles} = require('../../src/utils/fs.utils');
  
      const result = await getNumberOfFiles('targetDir');
      expect(result).toEqual(3);
      // you might stop assert this as well
      // expect(readdirSyncMock.mock.calls.length).toEqual(1);
    });
  });
});

还想检查一下,您是否按照此处所述创建了配置文件:https://www.npmjs.com/package/config#quick-start