Jest - how to check if a function is called by another function - javascript

I'm using Jest to test some Javascript. In a file, called 'function.js' I have two functions like so:
functions.js
const firstFunc = () => {
const x = secondFunc()
return x
}
const secondFunc = () => {
return '5'
}
module.exports = {
firstFunc,
secondFunc
}
In my Jest test file I have:
const functions = require('./functions.js')
test('test if secondFunc is called', () => {
const mockFunction = jest.fn()
functions.secondFunc = mockFunction;
functions.firstFunc()
expect(mockFunction).toHaveBeenCalled()
})
I've actually tried many different variations of things like this. I'm unable to get jest.fn() to work I want it to. Overall I'm wanting to be able to see information about secondFunc, such as how many times it was called, what parameters with, etc, but I have to actually call firstFunc. Can anyone help me as I can't seem to figure this out.

You need to do some refactoring. Keep the same reference for secondFunc.
Then you can replace it with a mocked object.
functions.js:
const firstFunc = () => {
const x = exports.secondFunc();
return x;
};
const secondFunc = () => {
return '5';
};
exports.firstFunc = firstFunc;
exports.secondFunc = secondFunc;
unit test result:
PASS stackoverflow/62583841/functions.test.js (12.17s)
✓ test if secondFunc is called (3ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 13.779s

Related

Javascript New Function - Best way to pass large number of functions as parameter

In angular project and learning to build a feature to run a custom script using the new function method. With the great help from this forum I have been able to come up with core script solution.
The question I have if I have a large number of custom functions I need to pass into New Function to access what would be the best method?
So far I have 2 options:
Option 1.
Passing each function as parameter. My concern if there is 50 plus function this could look messy.
eg
const userFunction = new Function('testFunc1','testFunc2','testFunc3'...'testFunc50', script);
Option 2.
Nest the functions in parent function. The draw back is to access the function we need to call the parent function which again can look messy in the code writing. Eg
parentFunc().nestFunc().
Question is there a better way to do this?
Code and stackblitz below.
https://stackblitz.com/edit/angular-bx5kia?file=src/main.ts
option1() {
var nestFunc1 = () => {
alert('Nest1');
};
var nestFunc2 = () => {
alert('Nest2');
};
const script = `
var value = 1 +4;\n
console.log('value',value);\n
nestFunc1();\n
console.log("End Script");\n
`;
const userFunction = new Function('nestFunc1', 'nestFunc2', script);
userFunction(nestFunc1, nestFunc2);
}
option2() {
const script = `
var value = 1 +4;\n
console.log('value',value);\n
parentFunc().nestFunc2();\n
console.log("End Script");\n
`;
var parentFunc = (msg?: string) => {
console.log('Test Function', msg);
var nestFunc1 = () => {
alert('Nest 1');
};
var nestFunc2 = () => {
alert('Nest 2');
};
return { nestFunc1, nestFunc2 };
};
const userFunction = new Function('parentFunc', script);
userFunction(parentFunc);
}
Well, I'm not an expert with Angular but as we are working with JS maybe I can give you some light in plain JS and then you can convert it to Angular syntax.
In JS you can write functions inside an array:
const functions = [
() => console.log( 'Nest 1' ),
() => console.log( 'Nest 2' )
]
And then, in your userFunction you can make a loop inside this array calling all functions:
const userFunction = ( functionsArray ) => {
functionsArray.forEach( nestedFunction => nestedFunction() )
}
Hope I can give you any idea :)

Testdouble usage of td.when not getting invoked inside td.object

Probably my misunderstanding of Testdouble, but I've created this example to illustrate the issue I'm having:
const test = require("ava");
const td = require("testdouble");
const reducer = async (state, event) => {
if (event.id === "123") {
const existing = await state.foo("", event.id);
console.log("existing:", existing);
}
};
test("foo", async (t) => {
const foo = td.func(".foo");
const state = td.object({
foo
});
td.when(foo(td.matchers.anything(), td.matchers.anything())).thenResolve({
id: "123"
});
await reducer(state, {
id: "123",
nickname: "foo"
});
});
This logs: existing: undefined
Whereas I believe it should log: existing: { id: "123" } as stated by the td.when()
What am I missing?
I think your issue is that td.object doesn't work the way you think it does:
td.object(realObject) - returns a deep imitation of the passed object, where each function is replaced with a test double function named for the property path (e.g. If realObject.invoices.send() was a function, the returned object would have property invoices.send set to a test double named '.invoices.send')
Source: https://github.com/testdouble/testdouble.js#tdobject
So when you do…
const foo = td.func();
const obj = td.object({foo});
… you're actually mocking foo twice.
Here's a demo:
const td = require('testdouble');
const num2str = td.func('num->string');
td.when(num2str(42)).thenReturn('forty two');
td.when(num2str(43)).thenReturn('forty three');
td.when(num2str(44)).thenReturn('forty four');
const x = {num2str};
const y = td.object({num2str});
num2str(42);
x.num2str(43);
y.num2str(44);
Then we can inspect x.num2str and we can see that it is the same test double as num2str:
td.explain(x.num2str).description;
/*
This test double `num->string` has 3 stubbings and 2 invocations.
Stubbings:
- when called with `(42)`, then return `"forty two"`.
- when called with `(43)`, then return `"forty three"`.
- when called with `(44)`, then return `"forty four"`.
Invocations:
- called with `(42)`.
- called with `(43)`.
*/
However y.num2str is a completely different test double:
td.explain(y.num2str).description;
/*
This test double `.num2str` has 0 stubbings and 1 invocations.
Invocations:
- called with `(44)`.
*/
I think what you're looking for is the "property replacement" behaviour of td.replace:
const z = {
str2num: str => parseInt(str),
num2str: num => {
throw new Error('42!');
}
};
td.replace(z, 'num2str');
td.when(z.num2str(42)).thenReturn('FORTY TWO!!');
The z.str2num function hasn't been mocked:
z.str2num("42");
//=> 42
However z.num2str is a fully-fledged test double:
z.num2str(42);
//=> 'FORTY TWO!!'
td.explain(z.num2str).description;
/*
This test double `num2str` has 1 stubbings and 1 invocations.
Stubbings:
- when called with `(42)`, then return `"FORTY TWO!!"`.
Invocations:
- called with `(42)`.
*/

My spy function is not getting called - how can I properly spy this function?

I'm trying to do call a function that is imported as a function independently in another function that I'm calling from my unit test. How can I get callcount of 1 on the functionIWantToSpy in this scenario?
auditEvent.js:
const { verify } = require('#mycompany/verifylib');
const { functionIWantToSpy } = require('#mycompany/another-lib');
const auditEvent = () => {
verify();
functionIWantToSpy();
};
module.exports = { auditEvent };
test:
const { verify } = require('#mycompany/verify-lib');
const { functionIWantToSpy } = require('#mycompany/another-lib');
describe('mytest', () => {
let spiedFuntion;
let verifyStub;
beforeEach(() => {
verifyStub = sinon.stub();
({auditEvent} = proxyquire('./auditEvent', {
'#mycompny/verify-lib': {
verify: verifyStub,
'#noCallThru': true,
},
}));
spiedFunction = sinon.spy(functionIWantToSpy);
});
it('should work'), async () => {
auditEvent();
expect(functionIWantToSpy).to.have.callCount(1); // Getting callcount of 0 here...
});
});
Spying involves replacing the function with a new function. You are replacing what is referred to by the identifier functionIWantToSpy so that it refers to a new spy function, instead of the original function referred to by require('#mycompany/another-lib').functionIWantToSpy. The code inside the module can't see your new spy function. The expression require('#mycompany/another-lib').functionIWantToSpy refers to the original function, unchanged.
Because require caches results (i.e., only the first require("foo") executes foo, and any subsequent require("foo") summons up that same object returned by the first require call), you can modify the functionIWantToSpy method of the require('#mycompany/another-lib') object, using the two-argument form of sinon.spy:
spiedFunction = sinon.spy(require('#mycompany/another-lib'), "functionIWantToSpy");
You must do this before the property is ever accessed (and value stored) by the module being tested:
verifyStub = sinon.stub();
// IMPORANT: FIRST, spy the functionIWantToSpy property on the required object before importing auditEvent
spiedFunction = sinon.spy(require('#mycompany/another-lib'), "functionIWantToSpy");
({auditEvent} = proxyquire('./auditEvent', {
'#mycompny/verify-lib': {
verify: verifyStub,
'#noCallThru': true,
},
}));
This should work because when the auditEvent module runs for the first time and gets to
const { functionIWantToSpy } = require('#mycompany/another-lib');
then require('#mycompany/another-lib').functionIWantToSpy will refer to the spy function.

Unit Testing JS - using JEST

Beginner Level - Unit Testing
Here's the function
export function toHex(number) {
const nstr = number.toString(16);
if (nstr.length % 2) {
return `0${nstr}`;
}
return nstr;
Able to figure out if the function is true or not by running the following Unit testing code:
// testing new function
describe('toHex', () => { //mocking the method
test('Testing Function toHex ', () => { // declaring the method
const str = 14 // initial value
const actual = toHex(str) // calculate the value
expect(actual).toMatchSnapshot(); // checking whether is true
})
});
Now how could I add different scenarios and make the following function to pass / Fail
Thanks

how do you create a stub/spy for an non-returned/parallel asynchronous function?

In this example, barStub.called === false, presumably because the execution flow of fooStub does not wait for barStub to resolve.
I also put assert(barStub.called) in a 10 sec setTimeout, and it still was uncalled.
Is there a way to stub a method like bar?
const sinon = require('sinon')
const assert = require('assert')
const functionHolder2 = {
bar: function() {
return Promise.resolve('bar')
}
}
const functionHolder = {
foo: function() {
functionHolder2.bar()
return Promise.resolve('foo')
}
}
const fooStub = sinon.stub(functionHolder, 'foo').returns(Promise.resolve({}))
const barStub = sinon.stub(functionHolder2, 'bar').returns(Promise.resolve({}))
functionHolder.foo()
assert(fooStub.called) // this passes
assert(barStub.called) // this fails
The problem here is that a stub replaces the functionality of the function you are stubbing.
This means that when you stub foo to return a promise, it totally replaces the original foo function.
What you need to do is spy on foo, which will keep its original functionality and flow, while allowing you to find out if its been called and how many times etc.
The actual stubbing of bar is correct - its just that the stub will never actually get called.
What you want (including waiting for the foo call to finish):
const sinon = require('sinon');
const assert = require('assert')
const functionHolder2 = {
bar: function() {
return Promise.resolve('bar')
}
}
const functionHolder = {
foo: function() {
functionHolder2.bar()
return Promise.resolve('foo')
}
}
const fooStub = sinon.spy(functionHolder, 'foo')
const barStub = sinon.stub(functionHolder2, 'bar').returns(Promise.resolve({}))
functionHolder.foo().then(() => {
assert(fooStub.called)
assert(barStub.called)
});
Documentation link: http://sinonjs.org/releases/v4.1.2/spies/

Categories