Sinon Spy to check function has been called - javascript

I am trying to use sinon.spy() to check that a function has been called. The function is called getMarketLabel and it returns marketLabel and accepts it into the function. I need to check that getMarketLabel has been called. I actually call getMarketLabel in one place, like so:
{getMarketLabel(sel.get('market'))}
The code I have so far is:
describe('Check if it has been called', () => {
let spy;
beforeEach(() => {
spy = sinon.spy(getMarketLabel, 'marketLabel');
})
it('should have been called', () => {
expect(spy).to.be.calledWith('marketLabel');
});
});
This is the error I receive:
TypeError: Attempted to wrap undefined property marketLabel as function

Sinon can't spy on functions that aren't a property of some object, because Sinon has to be able to replace the original function getMarketLabel by a spied-on version of that function.
A working example:
let obj = {
getMarketLabel(label) {
...
}
}
sinon.spy(obj, 'getMarketLabel');
// This would call the spy:
obj.getMarketLabel(...);
This syntax (which is close to what you're using) also exists:
let spy = sinon.spy(getMarketLabel);
However, this only triggers the spy code when explicitly calling spy(); when you call getMarketLabel() directly, the spy code isn't called at all.
Also, this won't work either:
let getMarketLabel = (...) => { ... }
let obj = { getMarketLabel }
sinon.spy(obj, 'getMarketLabel');
getMarketLabel(...);
Because you're still calling getMarketLabel directly.

This is the error I receive: TypeError: Attempted to wrap undefined
property marketLabel as function
You need to require the helper.js into your test file, then replace the relevant method on the required module and finally call the method replaced with the spy:
var myModule = require('helpers'); // make sure to specify the right path to the file
describe('HistorySelection component', () => {
let spy;
beforeEach(() => {
spy = sinon.stub(myModule, 'getMarketLabel'); // replaces method on myModule with spy
})
it('blah', () => {
myModule.getMarketLabel('input');
expect(spy).to.be.calledWith('input');
});
});
You cannot test whether the spy is called with helpers.sel('marketLabel') as this function will be executed before the test is conducted. You will therefore by writing:
expect(spy).to.be.calledWith(helpers.sel('marketLabel'));
be testing that that the spy is called with whatever value returned by helpers.sel('marketLabel') (which is undefined by default).
The content of helper.js should be:
module.exports = {
getMarketLabel: function (marketLabel) {
return marketLabel
}
}

Related

How to spy a function in Jest that would run on set?

I have an object like this:
const obj = {
}
And I want to transform it and add a method, and that method will run if a prop exist in that object.
function transform(obj){
obj.test = () => {
//Do something
}
if(obj.target){
obj.test()
}
}
transform(obj)
How can I test if this function has run or not? If using jest.spyOn, I can only spy on it after this method has been added to the obj, which by then the method has already run.
EDIT
This is the actual code and the test I am struggling with:
https://github.com/winston0410/camouflage/blob/1811aa85e6f3f966636c3d28f26b91941456a03a/tests/hydration.test.js#L33-L45

Jest: having trouble keeping a reference of a mock function with `jest.fn()`

I wanted to mock out a function and make sure it has executed a certain number of times.
The tricky part is that the function I wanted to mock out is part of the returned result of another function
My implementation is roughly like
const theFnIWantedToMock = jest.fn()
jest.mock('../hooks', () => {
const actualHooks = jest.requireActual('../hooks')
return {
...actualHooks,
someHooks() {
return
{
theFnIWantedToMock,
}
}
}
})
describe('test', () => {
it('some test', () => {
//...
expect(theFnIWantedToMock).toHaveBeenCalledTimes(1)
})
})
but Jest is throwing an error saying that Invalid variable access theHookINeedToMock. Does anyone know what is the correct way of doing it?
This problem is described in the documentation:,
A limitation with the factory parameter is that, since calls to jest.mock() are hoisted to the top of the file, it's not possible to first define a variable and then use it in the factory. An exception is made for variables that start with the word 'mock'. It's up to you to guarantee that they will be initialized on time! For example, the following will throw an out-of-scope error due to the use of 'fake' instead of 'mock' in the variable declaration
Prefixing a variable with mock disables Jest check. let or const variables are in temporal dead zone before declaration, that they are accessed when a factory is evaluated results in runtime error in untranspiled ES6. For eagerly evaluated mocked modules a mock needs to be defined inside a factory.
A way to avoid this is to use var declaration that is hoisted and initialize it inside a factory:
var theFnIWantedToMock
jest.mock('../hooks', () => {
const actualHooks = jest.requireActual('../hooks')
theFnIWantedToMock = jest.fn()
return {
...actualHooks,
someHooks: jest.fn().mockReturnValue(theFnIWantedToMock),
}
})
A way to keep a reference to it is to keep it a part of the import:
jest.mock('../hooks', () => {
const actualHooks = jest.requireActual('../hooks')
const theFnIWantedToMock = jest.fn()
return {
...actualHooks,
theFnIWantedToMock,
someHooks: jest.fn().mockReturnValue(theFnIWantedToMock),
}
})
This makes theFnIWantedToMock available as a part of import object, also works for reusable mocks in __mocks__.

Jest: how to count call from mock methods called via `call` or `apply`?

How can I use mocks to count function calls made via call or apply
// mylib.js
module.exports = {
requestInfo: function(model, id) {
return `The information for ${model} with ID ${id} is foobar`;
},
execute: function(name) {
return this[name] && this[name].apply(this, [].slice.call(arguments, 1));
},
};
// mylib.test.js
jest.mock('./mylib.js');
var myLib = require('./mylib.js');
test('', () => {
myLib.execute('requestInfo', 'Ferrari', '14523');
expect(myLib.execute.mock.calls.length).toBe(1); // Success!
expect(myLib.requestInfo.mock.calls.length).toBe(1); // FAIL
});
If I explicitly call myLib.requestInfo, the second expectation succeeds.
Is there a way to watch module mock calls whose functions were called via apply or call?
From the jest.mock doc:
Mocks a module with an auto-mocked version when it is being required.
The docs could probably be improved with a better description of what "auto-mocked version" means, but what happens is that Jest keeps the API surface of the module the same while replacing the implementation with empty mock functions.
So in this case execute is getting called but it has been replaced by an empty mock function so requestInfo never gets called which causes the test to fail.
To keep the implementation of execute intact you will want to avoid auto-mocking the entire module and instead spy on the original function with something like jest.spyOn:
var myLib = require('./mylib.js');
test('', () => {
jest.spyOn(myLib, 'execute'); // spy on execute
jest.spyOn(myLib, 'requestInfo') // spy on requestInfo...
.mockImplementation(() => {}); // ...and optionally replace the implementation
myLib.execute('requestInfo', 'Ferrari', '14523');
expect(myLib.execute.mock.calls.length).toBe(1); // SUCCESS
expect(myLib.requestInfo.mock.calls.length).toBe(1); // SUCCESS
});

How in Mocha test function with console.log statement?

Let's say, I have a function:
function consoleOutput(param) {
var newParam = param * param;
console.log(newParam);
}
How can I test in Mocha, that this function will be working correctly (param will be multiplied by two and output to the console). Thanks.
A great library for these types of tests is Sinon. It can be used to "hook" existing functions and track how those functions get called.
For example:
const sinon = require('sinon');
const assert = require('assert');
// the function to test
function consoleOutput(param) {
var newParam = param * param;
console.log(newParam);
}
it('should log the correct value to console', () => {
// "spy" on `console.log()`
let spy = sinon.spy(console, 'log');
// call the function that needs to be tested
consoleOutput(5);
// assert that it was called with the correct value
assert(spy.calledWith(25));
// restore the original function
spy.restore();
});
The advantage of this is that you don't need to change the original function (which, in this case, isn't a big deal, but may not always be possible in larger projects).

Testing callback called after a event trigger with Sinon Js

It's my first test on Javacript with Mocha/Sinon/Chai And I don't know if it's possible to do this :
var obj = {
first : function () {
console.log('make job 1');
}
};
var objManager = function() {
$(document).on('event1', obj.first);
};
new objManager();
var spy = sinon.spy(obj, 'first');
describe('Test', function () {
it('My first test', function () {
$(document).trigger('event1');
spy.should.not.have.been.called;
});
});
My spy isn't called and don't understand why... My function "obj.first" has printed "make job 1".
if I modify my test by :
it('My first test', function () {
obj.first();
spy.should.not.have.been.called;
});
My spy is called.
So my question is : How make sinon spy work with a event ?
The problem is that you first bind the function to the event and then replace the function in obj with the spy. Doing this will not have any effect on the function you have bound to the event cause this is still the original function.
Do test this you have to create the spy before instantiate your objManager.

Categories