maddie
maddie

Reputation: 1954

Jest: child_process.exec.mockImplentation is not a function

I have a function that uses the child_process.exec function:

//serverUtils.js:
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);

  async getUpstreamRepo() {
    try {
      const forkConfig = (await exec('git remote get-url upstream')).stdout;
      let upstreamRepo = forkConfig.replace('[email protected]:', '');
      upstreamRepo = upstreamRepo.replace(/\r?\n|\r/g, '');
      return upstreamRepo;
    } catch (error) {
      console.error(error);
      throw error;
    }
  },

After looking at this SO post, I tried to mock the exec call like so:

//serverUtils.test.js:
const child_process = require('child_process');
jest.mock('child_process')
describe('Test Class', () => {
    ....
    it('check upstream repo', async () => {      

    child_process.exec.mockImplentation(jest.fn().
        mockReturnValueOnce('[email protected]:mock/url.git'))

    await expect(serverScript.getUpstreamRepo()).
        resolves.toEqual('mock/url.git');
    });
 }

However, I get child_process.exec.mockImplentation is not a function As the linked post explains, "Jest documentation says that when mocking Node's core modules calling jest.mock('child_process') is required." -- which I clearly do.

Upvotes: 2

Views: 2872

Answers (1)

mgarcia
mgarcia

Reputation: 6325

The error you are seeing is because you are calling mockImplentation instead of mockImplementation. Unfortunately, when you correct that typo the test still will not pass.

This is because you are calling promisify on exec method, allowing it to be used as a promise. What promisify does under the hood is transform from an asynchronous callback based function (where the callback is placed at last parameter and is called with error as first parameter and data as second) to a promise based function.

So, in order for the promisify method to work, you will have to mock the exec method so that it calls the callback parameter in order for the promise to resolve.

Also, note that you are reading the stdout parameter from the result of the exec call, so in the returned data you will have to send an object with that property.

Having all that into account:

it('check upstream repo', async () => {
    child_process.exec.mockImplementation((command, callback) => {
        callback(null, { stdout: '[email protected]:mock/url.git' });
    });

    await expect(serverScript.getUpstreamRepo()).
        resolves.toEqual('mock/url.git');
});

Another posible solution is to directly mock the promisify method:

jest.mock('util', () => ({
    promisify: jest.fn(() => {
        return jest.fn().mockResolvedValue({ stdout: '[email protected]:mock/url.git' });
    })
}));

describe('Test Class', () => {
    it('check upstream repo', async () => {
        await expect(serverScript.getUpstreamRepo()).
            resolves.toEqual('mock/url.git');
    });
});

Upvotes: 5

Related Questions