My NodeJS app has a function readFilesJSON() that calls fs.readFile(), which of course invokes a callback with the parameters (err,data). The Jest unit test needs to walk both the error path and the data path.
My solution was to mock the call to fs.readFile() (see below). The mock function simply passes error or data based on test logic. This approach works when there is only one function being tested. The trouble I am seeing occurs when there are multiple functions that call fs.readFile(). Jest runs all the tests concurrently and the asynchronous nature of the functions mean that there is no guaranteed ordering to the calls to fs.readFile(). This non-deterministic behavior wrecks both the error/data logic and the parameter-checking logic using toHaveBeenCalledWith().
Does Jest provide a mechanism for managing independent usage of the mocks?
function readFilesJSON(files,done) {
let index = 0;
readNextFile();
function readNextFile() {
if( index === files.length ) {
done();
}
else {
let filename = files[index++];
fs.readFile( filename, "utf8", (err,data) => {
if(err) {
console.err(`ERROR: unable to read JSON file ${filename}`);
setTimeout(readNextFile);
}
else {
// parse the JSON file here
// ...
setTimeout(readNextFile);
}
});
}
}
}
The injected function setup looks like this:
jest.spyOn(fs, 'readFile')
.mockImplementation(mockFsReadFile)
.mockName("mockFsReadFile");
function mockFsReadFile(filename,encoding,callback) {
// implement error/data logic here
}