Mocked Jest callback method not called

Viewed 834

I'm testing the NodeJS function/module below using jestjs

const fs = require("fs");
const path = require("path");
function read(filename, callback) {
  fs.readFile(path.join(__dirname, filename), { encoding: "utf-8" }, callback);
}

module.exports = {
  read,
};

The first test is:

  test("callback data returned is correct", (done) => {
    function callback(err, data) {
      try {
        expect(data).toBe("1");
        done();
      } catch (err) {
        done(err);
      }
    }
    read("./test", callback);
  });

and is succesful (I have an actual real test file with the contents being 1.

The second one is a bit trickier. Since I'm providing a mockCallback function to read, why isn't the callback called?

const { read } = require("./callback");

describe("callback testing", () => {
  test("callback is called", (done) => {
    const mockCallback = jest.fn((err, data) => data);
    read("./test", mockCallback);
    expect(mockCallback).toHaveBeenCalled();
    done();
  });
});

The test fails and while inspecting the mock function it seems it wasn't called.

I also tried adding the following in order to mock fs.readFile, without much success:

const mock = require("mock-fs");
const fs = require("fs");
jest.mock("fs");
  beforeEach(() => {
    mock({
      test: "1",
    });
  });

I'd like a solution that mocks the least of the dependant methods and an explanation as to why isn't the callback run.

1 Answers

You should mock fs.readFile method and trigger the callback in your test case.

E.g.

callback.js:

const fs = require('fs');
const path = require('path');

function read(filename, callback) {
  fs.readFile(path.join(__dirname, filename), { encoding: 'utf-8' }, callback);
}

module.exports = {
  read,
};

callback.test.js:

const { read } = require('./callback');
const fs = require('fs');

describe('callback testing', () => {
  test('callback is called', () => {
    const mockCallback = jest.fn();
    const mockData = 'mock file data';
    const mockReadFile = jest.spyOn(fs, 'readFile').mockImplementationOnce((filename, options, callback) => {
      callback(null, mockData);
    });
    read('./test', mockCallback);
    expect(mockCallback).toHaveBeenCalled();
    expect(mockReadFile).toBeCalledWith(expect.any(String), { encoding: 'utf-8' }, mockCallback);
    mockReadFile.mockRestore();
  });
});

unit test result:

 PASS  examples/65361608/callback.test.js
  callback testing
    ✓ callback is called (3 ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 callback.js |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.992 s, estimated 5 s
Related