Home > database >  Is it possible to mock a free-standing function in Javascript with Jest?
Is it possible to mock a free-standing function in Javascript with Jest?

Time:12-04

There are many questions on StackOverflow about how to mock things with Jest. I have, indeed, read many of those suggestions. I have experience with jest.mock and spyOn. I've tried the trick of doing a real import and overwriting just the function I desire to mock and have also tried the old import * as math from './math.js' and then you try to spyOn math but if you try it, you'll see that this won't work.

But after quite a lot of experimentation, I'm beginning to conclude that this is fundamentally impossible (which actually feels correct to me). The "real" subtract function that calls add will only ever be able to call the add defined in that module.

KEY POINT: The math.js file can NOT be edited. You cannot change it so that you have add and subtract as properties hanging off of some object. Consider that the math.js file is etched in stone and cannot be modified in any way.

I would LOVE to be wrong about this, but it seems to me that the free-standing add function in the math.js file cannot be mocked such that when you call the "real" subtract function, it runs the mocked add function. I know you could mock add and have mock add call a mocked subtract, but that is not the goal here.

Please consider this a purely academic question. This is not an XY problem. This is not a case of "what are you trying to do; there is a better way." This is purely trying to understand how things work given the fixed constraints I've outline in the question. Thanks!

math.js

export function add(a, b) {
   return a b;
}

export function subtract(a, b) {
   return add(a, -b);
}

math.test.js

import { subtract } from './math.js';

// mock the add function to return 1234

describe('math', () => {
   it('should return 1234', () => {
      expect(subtract(5,3)).toBe(1234);
   });
});

CodePudding user response:

It is not possible to mock a free-standing function in Javascript with Jest if that function is not a property of an object. In your example, the add function is not a property of any object, so it cannot be mocked in the way you described.

However, if you were able to modify the math.js file, you could change the add and subtract functions to be properties of an object, like this:

const math = {
  add(a, b) {
    return a b;
  },
  subtract(a, b) {
    return this.add(a, -b);
  }
}

export default math;

With this change, you could then mock the add function by doing the following in your test:

import math from './math.js';

jest.mock('./math.js', () => {
  const originalMath = jest.requireActual('./math.js');
  return {
    ...originalMath,
    add: jest.fn(() => 1234)
  }
});

describe('math', () => {
  it('should return 1234', () => {
    expect(math.subtract(5,3)).toBe(1234);
  });
});

This will mock the add function and have it return 1234 when math.subtract is called in the test. However, as mentioned, this assumes that you are able to modify the math.js file to make add and subtract properties of an object. If you are unable to make this change, it is not possible to mock the add function in the way you described.

  • Related