Mukesh Jha
Mukesh Jha

Reputation: 944

Mocked copyFile and stat function not getting called in jest

I am trying to mock copyFile and stat method from fs modules(fs.promises). But the mocked function is not being called and instead the original functions are called though the test cases pass.

The testing function code is:

jest.doMock('fs', () => ({
    promises: {
        copyFile: (src = 'source', dest = 'destination') =>
            jest.fn().mockImplementation(async () => {
                console.log('Inside the mock function in copyFile, please get executed, got frustrated', src, dest);
                return Promise.resolve(false);
            }),
        stat: () =>
            jest.fn().mockImplementation(async () => {
                console.log('Inside the mock function in stat method, please get executed, got frustrated');
                return Promise.resolve(false); // Probably wrong datatype
            }),
    },
}));


describe('Testing implementation', () => {
    const sample = new MainFunction()
    test('Testing', async () => {
        expect(sample.demo()).toEqual(Promise.resolve(true));
    });
});

Actual Code which needs to be tested:

import * as fs from 'fs';
export class MainFunction {
   async demo(): Promise<any> {
    const fileName = 'C:/Users/Desktop/testing-file-dir/';
    const fileName1 = '/destination/'
    let filefound = (await fs.promises.stat(fileName)).isFile();
    await fs.promises.copyFile(fileName,fileName1);
    console.log(filefound, 'inside actual code');
    return Promise.resolve(true);
   }
}

Can someone please help regarding where I am going wrong ? I had thought of using jest.mock but it was also giving error so I followed this link https://github.com/facebook/jest/issues/2567 which suggested to try doMock. If someone knows better way to handle this mock function, it would be great.

Thanks !

Upvotes: 0

Views: 651

Answers (2)

Mukesh Jha
Mukesh Jha

Reputation: 944

Based upon slideshowp2's solution, I had to do this change in order to avoid the error as stated in this https://github.com/facebook/jest/issues/2567.

The actual file remains same while test file changes to:

jest.mock('fs', () => {
    const originalModule = jest.requireActual('fs'); // so as to not override other functions apart from below mentioned one's
    return Object.assign({ __esModule: true }, originalModule, {
        promises: {
            copyFile: jest.fn().mockImplementation((src, dest) => {
                // src, dest are parameters passed in copyFile from src to destination
                let source = 'some source'; // sample source file
                if (source === src) {
                    return true;
                } else {
                    throw Error;
                }
            }),
            stat: jest.fn().mockReturnThis(),
            isFile: jest
                .fn()
                .mockImplementationOnce(() => { // I had series of test so for first one I wanted false hence this part, else we can remove this and directly use .mockImplementation()
                    return false;
                })
                .mockImplementation(() => {
                    return true;
                }),
        },
    });
});
describe('Testing implementation', () => {
    const sample = new MainFunction();
    test('Testing', async () => {
    const actual = await sample.demo();
    expect(actual).toBeTruthy();
   });
});

Upvotes: 0

Lin Du
Lin Du

Reputation: 102497

You can use jest.mock(moduleName, factory, options), and you didn't mock the method chain call correctly. You should use mockFn.mockReturnThis() to return this context to the caller.

E.g.

index.ts:

import * as fs from 'fs';

export class MainFunction {
  async demo(): Promise<any> {
    const fileName = 'C:/Users/Desktop/testing-file-dir/';
    const fileName1 = '/destination/';
    let filefound = (await fs.promises.stat(fileName)).isFile();
    await fs.promises.copyFile(fileName, fileName1);
    console.log(filefound, 'inside actual code');
    return Promise.resolve(true);
  }
}

index.test.ts

import { MainFunction } from './';

jest.mock('fs', () => ({
  promises: {
    copyFile: jest.fn().mockImplementation((src = 'source', dest = 'destination') => {
      console.log('Inside the mock function in copyFile, please get executed, got frustrated', src, dest);
      return Promise.resolve(false);
    }),
    stat: jest.fn().mockReturnThis(),
    isFile: jest.fn().mockImplementation(() => {
      console.log('Inside the mock function in stat method, please get executed, got frustrated');
      return Promise.resolve(false);
    }),
  },
}));

describe('Testing implementation', () => {
  const sample = new MainFunction();
  test('Testing', async () => {
    const actual = await sample.demo();
    expect(actual).toBeTruthy();
  });
});

test result:

 PASS  examples/66429093/index.test.ts
  Testing implementation
    ✓ Testing (10 ms)

  console.log
    Inside the mock function in stat method, please get executed, got frustrated

      at Object.<anonymous> (examples/66429093/index.test.ts:12:15)

  console.log
    Inside the mock function in copyFile, please get executed, got frustrated C:/Users/Desktop/testing-file-dir/ /destination/

      at Object.<anonymous> (examples/66429093/index.test.ts:7:15)

  console.log
    Promise { false } inside actual code

      at MainFunction.<anonymous> (examples/66429093/index.ts:9:13)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        3.12 s, estimated 4 s

Upvotes: 1

Related Questions