title: How to mock a function with callback parameters in JestJS
body: <p>My NodeJS app has a function <code>readFilesJSON()</code> that calls <code>fs.readFile()</code>, which of course invokes a callback with the parameters <code>(err,data)</code>. The Jest unit test needs to walk both the error path and the data path.</p>
  <p>My solution was to mock the call to <code>fs.readFile()</code> (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 <code>fs.readFile()</code>. Jest runs all the tests concurrently and the asynchronous nature of the functions mean that there is no guaranteed ordering to the calls to <code>fs.readFile()</code>. This non-deterministic behavior wrecks both the error/data logic and the parameter-checking logic using <code>toHaveBeenCalledWith()</code>.</p>
  <p>Does Jest provide a mechanism for managing independent usage of the mocks?</p>
  <pre><code>function readFilesJSON(files,done) {
      let index = 0;
      readNextFile();
      function readNextFile() {
          if( index === files.length ) {
              done();
          }
          else {
              let filename = files[index++];
              fs.readFile( filename, &quot;utf8&quot;, (err,data) =&gt; {
                  if(err) {
                      console.err(`ERROR: unable to read JSON file ${filename}`);
                      setTimeout(readNextFile);
                  }
                  else {
                      // parse the JSON file here
                      // ...
                      setTimeout(readNextFile);
                  }
              });
          }
      }
  }
  </code></pre>
  <p>The injected function setup looks like this:</p>
  <pre><code>jest.spyOn(fs, 'readFile')
      .mockImplementation(mockFsReadFile)
      .mockName(&quot;mockFsReadFile&quot;);
  
  function mockFsReadFile(filename,encoding,callback) {
      // implement error/data logic here
  }
  </code></pre>