Using jest to mock fs causes conflicts with the config module

I am currently attempting to write unit tests for the following file:

import { readFileSync } from 'fs';
import logger from './logger.utils';

export const readFile = async (targetDir: string, fileName: string): Promise<string> => {
  logger.info(`start reading from ${targetDir}/${fileName}`);
  const data = readFileSync(`${targetDir}/${fileName}`, {encoding: 'utf8', flag: 'r'});

  return data;
};

jest test file

import { mocked } from 'ts-jest/utils';
import fs from 'fs';
jest.mock('fs');
import * as fsUtils from '../../src/utils/fs.utils';

let readFileSyncMock: jest.SpyInstance;

describe('fs.utils', () => {
  describe('readFile', () => {
    afterEach(() => {
      readFileSyncMock.mockReset();
    });
    afterAll(() => {
      readFileSyncMock.mockRestore();
    });
    it('should create a new log directory if one doesn\'t already exist', async () => {
      mocked(fs.readFileSync as jest.Mock).mockImplementation(() => { ('some string') });
    
      const fileData = await fsUtils.readFile('target_directory', 'file_name');
    
      expect(fileData).toEqual('some string');
    });
  });
});

Upon running the test, I encounter the following error:

Config file /Users/dfaizulaev/Documents/projectname/config/runtime.json cannot be read. Error code is: undefined. Error message is: Cannot read property 'replace' of undefined

  1 | import loggingContext from './loggingContext';
> 2 | import config from 'config';
    | ^
  3 | import os from 'os';
  4 | import constants from '../../config/constants';
  5 |

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

The error is originating from the logger file that is being imported by the fs module file mentioned above.

logger.utils file

import loggingContext from './loggingContext';
import config from 'config';
import os from 'os';
import constants from '../../config/constants';

const LOG_LEVEL: string = config.get(constants.LOG_LEVEL);

....additional logic....

I suspect that the error is due to my incorrect mocking of the fs module, despite trying multiple approaches, I continue to receive this error.

Please share your guidance and insight.

Answer №1

The issue arose because I had been mocking the entire fs module, which is utilized in the config package.

I resolved this by removing jest.mock('fs'); and instead opting to mock the individual methods separately.

For instance:

import fs, { Stats, promises } from 'fs';
import * as fsUtils from '../../src/utils/fs.utils';

describe('fs.utils', () => {
  afterEach(() => {
    jest.resetAllMocks();
  });

  describe('statSync', () => {
    it('Should successfully call statSync', () => {
      jest.spyOn(fs, 'statSync').mockReturnValue({ size: 1000 } as Stats);
      const result = fsUtils.getFileSize('file path');
      expect(result).toEqual(1000);
    });
  });

  describe('writeFile', () => {
    it('Should successfully call writeFile', async () => {
      jest.spyOn(promises, 'writeFile').mockResolvedValue();
      await fsUtils.writeFile('file path', 'data');
    });
  });

  describe('readFile', () => {
    it('Should successfully call readFile', async () => {
      jest.spyOn(promises, 'readFile').mockResolvedValue('some file content');
      const result = await fsUtils.readFile('filePath', 'fileName');
      expect(result).toEqual('some file content');
    });
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The Disabled element does not exhibit effective styling

When we include the disabled attribute in the text element, the style does not work. Can you explain why? <input pInputText [style]="{'padding-bottom':'10px','padding-top':'10px','width':'100%&apos ...

Trouble encountered when using RxJS zip and pipe together

In my Angular Resolver, I am facing a scenario where I need to wait for two server calls. The catch is that the second server call is optional and can be skipped based on user input. This data retrieval process is crucial for loading the next page seamless ...

Can you explain the significance of the | symbol in TypeScript?

My journey with TypeScript is just beginning, and I recently encountered the symbol | while working on a problem in LeetCode using Typescript. I believe it has something to do with defining variable types. Can anyone provide more insight into this? /** ...

Having trouble getting the express router to function properly in your Node.js TypeScript project?

One of the components in this application is registerClass, where all routes are added. The source code is in the dist directory since this node app is using TypeScript. However, when calling the http://localhost:9001/user endpoint, it seems that it is not ...

Create a variety of URL formats for various object cases

Can you guide me on how to verify and create a URL under different circumstances? I am dealing with 3 cases that involve different types of objects: "repositories": { "toto": { "tata": "https://google.com/", ...

The system is unable to process the property 'items' due to a null value

When trying to access the properties of ShoppingCart, an error is encountered stating that Property item does not exist on type {}. The mistake made in the code is unclear and difficult to identify. shopping-cart.ts import { ShoppingCartItem } from &apos ...

What are the two different ways to declare a property?

I am trying to update my interface as shown below interface Student{ Name: String; age: Number; } However, instead of the current structure, I would like it to be like this interface Student{ Name: String; age | DOB: Number | Date; } This means t ...

Determine the maximum and minimum numbers by inputting a number and utilizing jQuery

<script type="text/javascript"> function findLargestNumber() { var number1, number2; number1 = Number(document.getElementById("N").value); number2 = Number(document.getElementById("M").value); if (number1 > numb ...

What is the process for transferring a Pulumi Output<T> to the container definition of a task in ECS?

When creating a generic ECS service that deals with dynamic data, it is important to note that the containerDefinition within a Task Definition must be provided as a single valid JSON document. The code snippet for this setup looks like: genericClientServi ...

Error encountered: ERESOLVE issue occurred while attempting to resolve dependencies during npm install

After attempting to run 'npm install' to download the dependencies from a cloned repository, an error appeared on the terminal. The operating system being used is Windows 10. npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: ...

I've encountered an error and am unsure of how to fix it

index.ts:5:8 - error TS1192: Module '"D:/Calculator/node_modules/@types/chalk-animation/index"' does not have a default export. 5 import chalkAnimation from "chalk-animation"; ~~~~~~ index.ts:22:1 - error TS1378: To ...

The input value "HH:MM" does not match the expected format of 'FormatOptions' for this parameter

I created a function that takes in two parameters: data and format. I am attempting to define an ENUM(FormatOptions) for the "format" parameter. However, I encountered the following error: Argument of type '"HH:MM"' is not compatible with param ...

What is the best way to loop through the keys of a generic object in TypeScript?

When I come across a large object of unknown size, my usual approach is to iterate over it. In the past, I've used generators and custom Symbol.iterator functions to make these objects iterable with a for..of loop. However, in the ever-evolving world ...

Change the type declaration of a list of elements to a list containing those elements organized within a container - Array<Wrapper<T>>

Is there a way to convert a plain array into an array of wrapped items in JavaScript? declare type MyGenericArray = [number, string, boolean] declare type WrappedGeneraicArray = Wrap<MyGenericArray> // WrappedGeneraicArr ...

The conditional type lacks proper restriction

I am facing an issue with my updateView function that is supposed to merge changes and update a view on the backend. The problem lies in not properly restricting what changes can be passed in based on the type of view. Below is an example of the code snipp ...

What is the process for combining two interface declarations into a single interface?

I have a question regarding organizing the properties of an interface: export interface IInvoicesData { invoice: IInvoice; invoiceWithTotals: IInvoice & IInvoiceTotals; } Currently, everything is functioning smoothly and I am able to consolid ...

"Upon the initial page load, the persistence of values in local storage using Next.js, React, and Recoil

Check out this code I have, const Layout: React.FC<LayoutProps> = ({ children }) => { const darkMode = useRecoilValue(darkModeAtom) console.log('darkMode: ', darkMode) return ( <div className={`max-w-6xl mx-au ...

When using the async pipe with Angular's ngFor, an error message indicates that the argument is

Can you explain why this error message is appearing: Argument of type '[string, { startTime: string; endTime: string; }][] | null' is not assignable to parameter of type 'Collection<unknown>'. It occurs when attempting to utilize ...

Reading files from multiple sources using Angular's FormArray

I am facing an issue with uploading multiple images from different inputs. I have a form set up with a formArray to add a new input each time the "Add file" button is clicked. this.designForm = this.fb.group({ newFiles: this.fb.array([ this.f ...

(TypeScript) Generate a type based on the input parameter type

Below is the code snippet I am working with: const Settings = { setting1: 10, setting2: true, }; type S = typeof Settings; function Process<M extends keyof S>(input: { option: M; value: S[M] }) { } If I try to call Process with an incorr ...