Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Mock `fs.promises.writeFile` with Jest

I am trying to mock the promise version of fs.writeFile using Jest, and the mocked function is not being called.

Function to be tested (createFile.js):

const { writeFile } = require("fs").promises;

const createNewFile = async () => {
    await writeFile(`${__dirname}/newFile.txt`, "Test content");
};

module.exports = {
    createNewFile,
};

Jest Test (createFile.test.js):

const fs = require("fs").promises;
const { createNewFile } = require("./createFile.js");

it("Calls writeFile", async () => {
    const writeFileSpy = jest.spyOn(fs, "writeFile");

    await createNewFile();
    expect(writeFileSpy).toHaveBeenCalledTimes(1);

    writeFileSpy.mockClear();
});

I know that writeFile is actually being called because I ran node -e "require(\"./createFile.js\").createNewFile()" and the file was created.

Dependency Versions

  • Node.js: 14.1.0
  • Jest: 26.6.3

-- Here is another attempt at the createFile.test.js file --

const fs = require("fs");
const { createNewFile } = require("./createFile.js");

it("Calls writeFile", async () => {
    const writeFileMock = jest.fn();

    jest.mock("fs", () => ({
        promises: {
            writeFile: writeFileMock,
        },
    }));

    await createNewFile();
    expect(writeFileMock).toHaveBeenCalledTimes(1);
});

This throws the following error:

ReferenceError: /Users/danlevy/Desktop/test/src/createFile.test.js: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: writeFileMock
like image 997
Dan Levy Avatar asked Mar 02 '23 21:03

Dan Levy


1 Answers

Since writeFile is destructured at import time instead of being consistently referred as fs.promises.writeFile method, it cannot be affected with spyOn.

It should be mocked as any other module:

jest.mock("fs", () => ({
  promises: {
    writeFile: jest.fn().mockResolvedValue(),
    readFile: jest.fn().mockResolvedValue(),
  },
}));

const fs = require("fs");

...

await createNewFile();
expect(fs.promises.writeFile).toHaveBeenCalledTimes(1);

It make sense to mock fs scarcely because unmocked functions provide side effects and potentially have negative impact on test environment.

like image 168
Estus Flask Avatar answered Mar 11 '23 03:03

Estus Flask