11

I am trying to mock a function in a third-party node module, specifically the fs.readFileSync() function, using jest. There are quite a few examples out there but I haven't found one which uses TypeScript. I have a simple, hopefully minimal, example at github. This is probably a simple issue for someone familiar with jest.

1
  • Yes, Mr Cantarela, typescript is Microsoft's take on javascript. I did start out with FB's Flow, but found that typescript combined with vscode was quite good so it seemed worthwhile pursuing a combination of typescript/jest(js) :). Commented Aug 31, 2018 at 21:44

1 Answer 1

19

Here are a few different ways of mocking something like fs.readFileSync():

Mock the function

To mock a function use jest.spyOn() in combination with functions like mockImplementation():

import { returnNameInJsonFile } from './index';
import * as fs from 'fs';

describe('index', () => {

  it('returnNameInJsonFile', () => {
    const mock = jest.spyOn(fs, 'readFileSync');  // spy on fs.readFileSync()
    mock.mockImplementation(() => JSON.stringify({ name: 'myname' }));  // replace the implementation

    const name: string = returnNameInJsonFile('test.json');
    expect(name).toBe('myname');

    mock.mockRestore();  // restore fs.readFileSync()
  });

});

Mock the module using a factory

Pass a module factory to jest.mock():

import { returnNameInJsonFile } from './index';

jest.mock('fs', () => {
  const MOCK_FILE_INFO = { 'test.json': JSON.stringify({ name: 'myname' }) };
  return {
    readFileSync: (fpath, opts) => {
      if (fpath in MOCK_FILE_INFO) {
        return MOCK_FILE_INFO[fpath]
      }
      throw 'unexpected fpath'
    }
  }
});

describe('index', () => {
  it('returnNameInJsonFile', () => {
    const name: string = returnNameInJsonFile('test.json');
    expect(name).toBe('myname'); // 1.0.0 is installed and 2.0.0 is available
  });
});

Mock the module automatically

Create a mock for the module.

Jest will use the mock automatically unless it is a core Node module (like fs) in which case calling jest.mock() is required.

__mocks__/fs.ts:

const fs = jest.genMockFromModule('fs');

let mockFiles: object = {};

function __setMockFiles (newMockFiles: object) {
  mockFiles = newMockFiles;
}

function readFileSync(filePath: string) {
  return mockFiles[filePath] || '';
}

// If anyone knows how to avoid the type assertion feel free to edit this answer
(fs as any).__setMockFiles = __setMockFiles;
(fs as any).readFileSync = readFileSync;

module.exports = fs;

index.test.ts:

import { returnNameInJsonFile } from './index';

jest.mock('fs');  // Required since fs is a core Node module

describe('index', () => {

  const MOCK_FILE_INFO = { 'test.json': JSON.stringify({ name: 'myname' }) };

  beforeEach(() => {
    require('fs').__setMockFiles(MOCK_FILE_INFO);
  });

  it('returnNameInJsonFile', () => {
    const name: string = returnNameInJsonFile('test.json');
    expect(name).toBe('myname'); // 1.0.0 is installed and 2.0.0 is available
  });
});
Sign up to request clarification or add additional context in comments.

4 Comments

this works for now - thanks! I've updated the github example
@nicky88 sounds like you wanted to mock the entire module, I updated my answer with a couple of ways of doing that
much appreciated, @brian-lives-outdoors .. I suspect it may be of use to others as well.
@brian-lives-outdoors this solution should work, but I'm getting an error back from Typescript that is frustrating to fix. Property '__setMockFiles' does not exist on type 'typeof import("fs")' I guess I'd need to "trick" TS into realizing there is a function on the 'fs' library (when mocked). And optionally (when using require inline): TypeError: require(...).__setMockFiles is not a function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.