How to mock functions called within the test function - javascript

I have module that contains several functions (foo, bar, etc).
// moduleA.js
const someModule = require('someModule')
const moduleA = () => {
const bar = (param1, param2) => {
// some implementation
}
const foo = (params) => {
// some implementation
bar(1, 2)
}
return Object.assign({}, someModule, {
foo,
bar
})
}
module.exports = moduleA
What I want to do is to mock other module functions (bar) being called within my current test (foo) function.
// jest test file
describe('Testing foo, mocking bar', () => {
const checker = moduleA()
it.only('When this, then that', async () => {
// THIS IS NOT WORKING
const spy = jest.spyOn(checker, "bar").mockReturnValue("XXXX")
const response = await checker.foo({ 1, 2, 3})
expect(response).toBeDefined()
})
})
What is the correct way to spy or stub the bar function so that I can mock the results and only focus testing the foo functionality?

Related

Using Jest with NodeJS, Function in imported module not being mocked without using 'this' in main

In the setup below, if I run the test as is, myFunc is not mocked when I debug into handler.
However, if instead I add this. in front of the myFunc call in handler, then the function is mocked and everything works as expected.
Can someone please explain why this is? I'm new to mocking and can't see it.
I know what this does, but why won't jest mock without it since I told it to mock that function in the module?
index.js
const aws = require('aws-sdk')
exports.handler = async function (event, context) {
let s;
switch (event.func) {
case "myFunc":
console.log('Executing myFunc');
//making the call: s = await this.myFunc.apply(null, [event.params]) will make the mock work.
s = await myFunc.apply(null, [event.params])
console.log(s);
return s;
/*cases...*/
default:
// default behaviour
}
async myFunc({p1, p2}){
/* do something */
return x
}
exports.myFunc = myFunc
}
index.spec.js
jest.mock('./index.js', () => {
const allAutoMocked = jest.createMockFromModule('./index.js')
const actual = jest.requireActual('./index.js')
return {
__esModules: true,
...allAutoMocked,
myFunc : jest.fn().mockImplementation(() => ({ mockedValue: 'test' })),
handler: actual.handler
}
})
let index = require("./index.js")
describe('Test myFunc', () => {
test('If myFunc function was called', async () => {
var event = { func: 'myFunc', params: { p1: xx, p2: false } };
const context = {};
const logMock = jest.fn((...args) => console.log(...args));
const data = await handler(event, context);
})
})

How to use Jasmine.js spy on a required function

I have this code (Node.js):
File: utils.js
// utils.js
const foo = () => {
// ....
}
const bar = () => {
// ....
}
module.exports = { foo, bar }
File: myModule.js
// myModule.js
const {
foo,
bar
} = require('./utils');
const bizz = () => {
let fooResult = foo()
return bar(fooResult)
}
module.exports = { bizz }
File: myModule.spec.js
// myModule.spec.js
const { bizz } = require('./myModule');
describe('myModule', () => {
it('bizz should return bla bla bla', () => {
let foo = jasmine.createSpy('foo').and.returnValue(true)
let bar = jasmine.createSpy('bar').and.callFake((data) => {
expect(date).toBeTrue();
return 'fake-data'
})
expect(bizz()).toBe('fake-data')
})
})
I'm trying to test bizz using spies on foo and bar functions but it's not working well.
Can anyone explain to me how to create spies on these functions with the purpose to test bizz??
Yes, it is possible.
You just need to require utils to spyOn first, then require myModule. The following test will pass.
const utils = require('./utils');
// myModule.spec.js
describe('myModule', () => {
it('bizz should return bla bla bla', () => {
const fooSpy = spyOn(utils, 'foo').and.returnValue(true);
const barSpy = spyOn(utils, 'bar').and.callFake(data => {
expect(data).toBeTrue();
return 'fake-data';
});
const { bizz } = require('./myModule'); // Import myModule after you added the spyOn
expect(bizz()).toBe('fake-data');
expect(fooSpy).toHaveBeenCalled();
expect(barSpy).toHaveBeenCalled();
});
});
Hope it helps
Seems like it's not possible. https://github.com/mjackson/expect/issues/169

Sinon Spy for Non-Class Methods

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]);
});
});
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".

Stub a function of a function with jest

I'm trying to stub a function of a function (well I need to stub both really)
Here is an example
return res.foo(100).bar(aVar)
and here is what my test mocking looks like
let res = {
foo: ()=> jest.fn( {bar:()=> jest.fn()})
}
However when running my tests I get the error 'TypeError: res.foo(...).bar is not a function'
You're close.
Just three changes needed:
jest.fn() returns a function so it doesn't need to be wrapped in a function
jest.fn() takes an optional implementation parameter which should be a function
If you want to spy on bar then return the same spy in the mock implementation of foo, otherwise a new bar spy gets created each time foo is called.
So your mock should look like this:
const barSpy = jest.fn();
let res = { foo: jest.fn(() => ({ bar: barSpy })) };
Here is a working demo:
const func = (res, aVar) => {
return res.foo(100).bar(aVar);
}
test('stub chained functions', () => {
const barSpy = jest.fn(() => 'the result');
const res = { foo: jest.fn(() => ({ bar: barSpy })) };
const result = func(res, 'a var');
expect(res.foo).toHaveBeenCalledWith(100); // SUCCESS
expect(barSpy).toHaveBeenCalledWith('a var'); // SUCCESS
expect(result).toBe('the result'); // SUCCESS
})

How to overwrite (or mock) a class method with Jest in order to test a function?

I have an issue with a unit test of a function which calls a class. It seems that it always calls the "official" class instance and not my mocked class. I'm not able to force my function to use my mocked instance...
There is a file with the function I want to test:
const myClass = require('./myClass');
const instance = new myClass();
module.exports.functionToTest = async function () {
// Some stuff...
const value = await instance.myMethod();
// Some stuff that define a result variable (partially with value).
return result;
}
There is a file with my class definition:
module.exports = class myClass {
async myMethod() {
const result = await someStuffWillResolveMaybeTrueOrFalse();
console.log('We used the original myMethod... Mocking has failed.');
return result;
}
}
There is a spec file:
const myFile = require('./myFile');
const myClass = require('./myClass');
describe('My test', async () => {
it('should mock myClass.myMethod in order to return false', () => {
const instance = new myClass();
instance.myMethod = jest.fn().mockResolvedValue(false);
const result = await myFile.functionToTest();
expect(result).toBeTruthy();
}
}
Unfortunately my test is passing (because myMethod return "true") and log "We used the original myMethod... Mocking has failed."
So I want to make my test always fail by mocking that myMethod to return false.
Can you help me? Thanks for your time.
Hm. I've found a solution.
See. A change in my file with the target function.
const myClass = require('./myClass');
// const instance = new myClass(); <== Not here...
module.exports.functionToTest = async function () {
const instance = new myClass(); // <== ...but there.
// Some stuff...
const value = await instance.myMethod();
// Some stuff that define a result variable (partially with value).
return result;
}
And my spec file :
const myFile = require('./myFile');
// I specify to Jest that I'll mock a file
jest.mock('./myClass');
const myClass = require('./myClass');
// I prepare the mock function. In that case a promise wich resolve 'false'
const mMock = jest.fn().mockResolvedValue(false);
// I mock the method 'myMethod' in 'myClass'
myClass.mockImplementation(() => {
return {
myMethod: mMock
};
});
// Then, I just take the test
describe('My test', async () => {
it('should mock myClass.myMethod in order to return false', () => {
const result = await myFile.functionToTest();
expect(result).toBeFalsy();
}
}

Categories