Jestjs how to test function being called inside another function

Dune picture Dune · Oct 4, 2018 · Viewed 30.4k times · Source

For testing I use jest and react-test-renderer. It should be simple to test, however I have a hard time finding the proper example. I have tried to do something like that (in general I keep the functions in separate files):

utils.js

export const childFunction = () => 'something';    
const parentFunction = () => childFunction();
export default parentFunction;

utils.test.js

import parentFunction from './utils.js';


it('childFunction should be called', () => {
 const childFunction = jest.fn();
 parentFunction();
 expect(childFunction).toBeCalled();
})

The fragment const childFunction = jest.fn(); definitely won't work. While calling, parentFunction's body cares only about its own scope. But it also won't work if I import childFunction and do jest.mock(childFunction), because jest.mock needs a string, a url to a module, and not the function itself.

The example above doesn't work and I'm searching for an alternative. However this works after rendering the component with ShallowRenderer. And I'd like to achieve a similar behaviour with a function nested inside another function.

class Component extends React.Component {
 componentDidMount() {parentFunction()}
 render() {...}
}

const renderer = new ShallowRenderer();
describe("testing parentFunction", () => {
  renderer.render(<Component/>);
  it("parentFunction should be called", () => {
    expect(parentFunction).toBeCalled();
  });
});

Answer

Dimitar Christoff picture Dimitar Christoff · Oct 4, 2018

not sure if this will help but it may give you ideas.

first, the example above:

// this needs to be stubbed
// const childFunction = () => 'something';
const childFunction = jest.fn();

const parentFunction = () => childFunction();

it('childFunction should be called', () => {
    parentFunction();
    expect(childFunction).toHaveBeenCalled();
}

this is a somewhat contrived example as it's unlikely that childFunction is exported so you cannot get a reference to it and mock/stub it.

one workaround you have would be to move it out into its own method

class Component extends React.Component {
  componentDidMount() {
    this.parentFunction();
  }
  parentFunction() {
    parentFunction(); // from elsewhere
  }
  render() {...}
}

This allows you to create a puncture and spy on the Component proto.

eg

const spy = jest.spyOn(Component.prototype, 'parentFunction');

// ... mount so lifecycle runs... 
expect(spy).toHaveBeenCalled(); // and clear the spy mocks after!

it may be better to mock the module

eg you have utils.js used by your component that does:

export function parentFunction(){ console.log('parent'); }

component.js does:

import { parentFunction } from './utils';

you could in your tests do:

const utils = require('./utils');
utils.parentFunction = jest.fn();
import Component from './component';
// later
expect(utils.parentFunction).toHaveBeenCalled();

as you can see, many possible ways to go, though I am not sure on the value of that test, you should probably test the output / functionality of the component rather than it had called, having something run on componentDidMount is a given and would only break if somebody converted to functional or changed the lifecycle name.