Mocking fs and glob modules with Jest

to test scripts that read and write files to disk.

Marek Rozmus
4 min readDec 6, 2023
Photo by benjamin lehman on Unsplash

The whole code can be found in this GitHub repository: https://github.com/marekrozmus/blog-mocking-fs-and-glob-modules-with-jest

When I had to introduce one more “small change” to one of the post build scripts in the project I had a lot of those thoughts like: “I hope this won’t break anything”. When you get that kind of thoughts — it is the time to write some unit tests ;)

The unit test should be if course written as soon as possible but sometimes there is no time as we need that feature now and it is already Friday afternoon (leave a clap if you have ever needed to make a Friday afternoon deployment ;)).

So this time (it was not Friday yet) I have decided to take some time to write the tests while I still understood what this script supposed to do.

The script was just searching for some HTML files in specific folder and was replacing some texts in those files — simple as that.

Find the files, find in those files specific texts (enclosed with some start and end markers), replace those with some new values and save the files.

What I wanted to test if the texts are found correctly and if those are replaced with expected data.

The code simplified

You can download the repo and run npm start to see the script in action: https://github.com/marekrozmus/blog-mocking-fs-and-glob-modules-with-jest

Mocking

To stop the fs and glob access the disk during the tests, they need to be mocked. This can be done by using following Jest method — Mocking Node modules.

So we need to create the mocks of those libraries in the __mocks__ folder.

In my case for the glob I needed only globSync method that was returning the “found” files. This is how whole glob mock look like in my case:

So just two functions — one for setting the files that should be returned (__setMockFiles) and another one that I used in the post build script (globSync).

The mock for the fs module looks almost the same:

It got the __setMockFiles function also but in this case we initialize that with the file path and its content.

For glob we take only files’ paths but for the fs module mock also the content of the files that will be returned by the readFileSync function.

And here is the test:

What is happening here:

  • spyOn the writeFileSync method to see if it is called with proper params
  • load and run the script (it will use the mocked glob and fs modules
  • check if the proper replacement is done

Remove console logs from test results

Because the script had some console.log calls, this is what I could see when tests were run:

I have tried something that worked in other projects: jest.spyOn(global.console, “log”).mockImplementationOnce(() => undefined);

But unfortunately still console logs were there. The solution was to show the logs only if script was run with specific param:

verbose && console.log(‘ Writing file…’);

Check the post-build.js file to see how it is used.

Disable automatic script run

The post build script had following structure:

That caused it to be run every time it was required. In the test the following line was already running the script const PostBuild = require(“./post-build”);

Then another line was triggering the script again: PostBuild.main();

One might say: just remove the second invocation. Well, this brings two issues:

  • we cannot see directly in the test that we actually have run something
  • if the main method would be async then it gets complicated to actually await until it is done

So I have updated the script to only run automatically if specific argument is used:

And then update the package.json script to pass that param:

And that’s it — now you we can run the script and test it.

--

--

Marek Rozmus
Marek Rozmus

Written by Marek Rozmus

Senior Frontend Engineer at GoStudent

No responses yet