Sinon Spy for Non-Class Methods

Asked by At

I have a javascript file with a bunch of util functions in a file called utils.js

export const processListOfItems = (input): [] => {
  let listOfItems = [];
  for (var index = 0; index < rawPayload.length; ++index) {
    listOfItems.push(someFunction(item));
  }
  return listOfItems;
};

someFunction is defined in utils.js as well.

For the test, I would like to stub "someFunction," but am having trouble figuring out how to do so. It looks like sinon.spy() might be the method I want, but it looks like it requires an object, of which I don't have one since it's just a utils file.

My ideal test would look something like this

describe('someFunction fails on an item', () => {
  it('returns the array with the rest of the items', () => {
    const items = ['hi', 'hello'];

    // I want to make it such that, when we go into the getListOfItems code, we return 42 whenever we call someFunction, rather than going into the logic itself.
    const someFunctionStub = sinon.stub(someFunction).returns(42);

    expect(getListOfItems(items)).toEqual([42, 42]);
  });
});

1 Answers

0
brian-lives-outdoors On

sinon.stub replaces a property on an object...

...and often the object is a module and the property is a function the module exports.

When the module export of a function is stubbed, any code that calls the module export of the function will then call the stub.


It isn't possible to stub someFunction in the code above since processListOfItems isn't calling the module export of someFunction, it is calling someFunction directly.

processListOfItems needs to call the module export of someFunction in order to be able to stub the call.


Here is a simple example to demonstrate using Node.js module syntax:

util.js

exports.func1 = () => {
  return 'hello ' + exports.func2();  // <= use the module
}

exports.func2 = () => 'world';

util.test.js

const sinon = require('sinon');
const util = require('./util');

describe('func1', () => {
  it('should work', () => {
    const stub = sinon.stub(util, 'func2').returns('everyone');
    expect(util.func1()).toBe('hello everyone');  // Success!
  });
});

...and here is a simple example using ES6 module syntax:

util.js

import * as util from './util';  // <= import module into itself

export const func1 = () => {
  return 'hello ' + util.func2();  // <= use the module
}

export const func2 = () => 'world';

util.test.js

import * as sinon from 'sinon';
import * as util from './util';

describe('func1', () => {
  it('should work', () => {
    const stub = sinon.stub(util, 'func2').returns('everyone');
    expect(util.func1()).toBe('hello everyone');  // Success!
  });
});

Note that ES6 modules can be imported into themselves since they "support cyclic dependencies automatically".