Ошибка получения Jest-кода при издевательстве над модулями FS и вызове модуля конфигурации

#jestjs #fs

#jestjs #fs

Вопрос:

Я пишу модульные тесты с помощью 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;
 

Я предполагаю, что config использует FS, и как только я издеваюсь над модулем, он выходит из строя.
Как я могу решить эту проблему? Пожалуйста, сообщите

Ответ №1:

Я предполагаю, что проблема возникает 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

Комментарии:

1. Попробовал ваше решение, получив эту ошибку Configuration property "LOG_LEVEL" is not defined из файла регистратора. В качестве конфигурации невозможно использовать модуль fs.