Sinon stub is not tracking consecutive methods invocation of the app - javascript

I'm trying to make a basic integration test using Karma, Sinon and Mocha, but it's not return the expected result.
The application has a simple flow:
todo.init --> calls todo.api.sendRequest({options Object}, callback) --> calls todo.setup
**todo.setup is being invoked by the callback when we get the response back.(from the sendRequest method)
var expect = chai.expect;
describe('API integration', function(){
it('todo.setup receives an array of todos when todo.init is called', function () {
// create a stub
sinon.stub(todo, 'setup');
// start the application
todo.init();
expect(todo.setup.called).to.be.true;
});
});
This test is not passing. If I invoke the todo.setup explicitly
var expect = chai.expect;
describe('API integration', function(){
it('todo.setup receives an array of todos when todo.init is called', function () {
// create a stub
sinon.stub(todo, 'setup');
// Invoke directly the todo.setup
todo.setup();
expect(todo.setup.called).to.be.true;
});
});
The test passes now, but it's not the correct behavior because i'm invoking manually the method instead the application call.

Related

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
});

Writing JavaScript tests that test other functions are called, without actually calling them

I have been tasked with writing unit tests for some AngularJS code that was written by another team, who didn't write any tests
They have written the following function but I cannot figure out how to test it
function showCallAlerts(callRecord, isInEditMode, callBack) {
var callAlerts = populateCallAlertOnEditCall(callRecord.callAlert);
var callModalInstance = openAlertModalInstance('Call', callAlerts, callBack);
if (callModalInstance !== undefined && callModalInstance !== null) {
callModalInstance.result.then(function() {
// Show equipment alerts based on company details
showEquipmentAlertsBasedOnCompanyDetails(callRecord, isInEditMode, callBack);
});
} else {
// Show equipment alerts based on company details
showEquipmentAlertsBasedOnCompanyDetails(callRecord, isInEditMode, callBack);
}
}
I need to test that each of the functions are called, not worrying about what they do as I'll test them separate, just that they are called.
When populateCallAlertOnEditCall is called it needs to either return an empty array or an array with some items in it
When openAlertModalInstance is called it needs to either return undefined or something that passes through to showEquipmentAlertsBasedOnCompanyDetails
showEquipmentAlertsBasedOnCompanyDetails should actually be called, I'll test that method separate, just that it was called
I have manged to write code to test simple functions but nothing like this one so any help will be much appreciated, I spent most of this afternoon trying to figure it out
You can use jasmine to mock the function calls that you are not interested in testing. For example, you can tell jasmine to return an empty array every time 'populateCallAlertOnEditCall' is called. I will write an example that might give you an insight:
describe('My Test Spec', function() {
var myController;
...
beforeEach( inject(($controller) => {
myController = $controller("myControllerName");
}));
it('Testing showCallAlerts when populateCallAlertOnEditCall returns an empty array', inject(function($controller) {
//setup
//this will replace every call to populateCallAlertOnEditCall with
//the function inside callFake
spyOn(myController, 'populateCallAlertOnEditCall ').and.callFake(function() {
return []; //returning an empty array.
});
//action
myController.showCallAlerts(...);
//assert
//Do your checking here.
}));
it('Testing showCallAlerts when populateCallAlertOnEditCall returns a non-empty array', inject(function($controller) {
//setup
//this will replace every call to populateCallAlertOnEditCall with
//the function inside callFake
spyOn(myController, 'populateCallAlertOnEditCall ').and.callFake(function() {
return [1,2,3,4]; //returning a non-empty array.
});
//action
myController.showCallAlerts(...);
//assert
//Do your checking here.
}));
});
the test that something has been called, you can use a Spy
your assertion would look like:
spyOn(obj, 'populateCallAlertOnEditCall')
expect(obj.method).toHaveBeenCalled()
UPDATED:
populateCallAlertOnEditCall = {}
spyOn(obj, 'populateCallAlertOnEditCall.result')
expect(obj.method).toHaveBeenCalled()
The kind of behaviour you want is called mocking
In Jasmine, mocking is done with Spy Objects, you can read more about those here
Basically, you can use mocks to test if functions were called with the expected parameters.
var xhr = mock( XMLHttpRequest );
xhr.send();
expect( xhr.send ).toHaveBeenCalled();

Angular, Jasmine - Spying on a function, being executed inside $interval/$timeout services

Good day!
I want to test whether parseUrl method is called, but as the result: test is failed - parseUrl was never called, although if I put the parseUrl() outside of the $interval service's function, then test pass successfully.
Here is the place, where parseUrl is called:
testMethod() {
let intervalPromise = this._$interval(() => {
this.parseUrl('test', 'test_code_name');
}, 500);
}
parseUrl(url, name) {}
Here is the test case:
it('Expect testMethod to be called', function () {
TestService.testMethod()
spyOn(TestService, 'parseUrl').and.callThrough();
expect(TestService.parseUrl).toHaveBeenCalled();
});
Also the fact is, if I put the testMethod() outside of the $interval service, then test pass successfully.
In your test you need to inject the $interval service (could use ngMock) and call $interval.flush(500);
var $interval;
angular.mock.inject(function (myModuleService, _$interval_) {
// Initialize the service under test instance
$interval = _$interval_;
});
it('Expect testMethod to be called', function () {
TestService.testMethod()
spyOn(TestService, 'parseUrl').and.callThrough();
$interval.flush(500);
expect(TestService.parseUrl).toHaveBeenCalled();
});
Here is a link to the docs: https://docs.angularjs.org/api/ngMock/service/$interval
Use $interval.flush(millis) to move forward by millis milliseconds and trigger any functions scheduled to run in that time.

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).

How can I fix this Q.denodify test?

I am using a database library that its callback-based interface looks like this:
var DB = {
insert: function(options, callback) {
}
}
I want to implement a wrapper around this database to convert its callback style API to a promise based API. To do this I have defined the following class:
var DatabaseWrapper = {
init: function(db) {
this.db = db;
},
insert: function(options) {
return Q.denodeify(this.db.insert.bind(this.db))(options);
}
}
I want to write a unit test to ensure that when I call DatabaseWrapper.insert it calls DB.insert. So far my test looks like this:
describe('DatabaseWrapper', function () {
var wrapper, insertSpy, bindStub;
beforeEach(function () {
wrapper = Object.create(DatabaseWrapper);
insertSpy = sinon.spy(function () {
console.log('insertSpy got called');
});
bindStub = sinon.stub();
wrapper.db = {
insert: function (options, callback) {
}
};
sinon.stub(wrapper.db.insert, 'bind').returns(insertSpy);
});
describe('#insert', function () {
it('should delegate to db.insert', function (done) {
wrapper.insert({herp: 'derp'});
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
// This fails but I expect it to succeed
expect(promise).to.have.been.calledOnce;
})
});
});
The DB instance's insert method is actually getting called as after the test fails, as the 'insertSpy got called' message is printed in the console.
But apparently it gets called after the test has failed.
As far as I know, this is due to the way Node's process.nextTick works. So the call to the callback happens after the test fails. Is there a way I can fix this test without relying on third-party libraries (e.g. q-flush)?
You're performing an asynchronous action so it's best to perform an asynchronous test. Adding a setTimeout still leaves you prone to race conditions.
describe('#insert', function () {
it('should delegate to db.insert', function () { // no done here
// note the return here to signal to mocha this is a promise test
return wrapper.insert({herp: 'derp'}).then(function(){
// add expects here, rest of asserts should happen here
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
});
})
});
});

Categories