jasmine mock second method - javascript

I am trying to do the following thing in Jasmine but not sure if it is possible :
I Got a service object with 2 methods, A and B.
Method A calls method B (B is in fact a $http call which I do not want to do during my test : I want to mock it).
In my BeforeEach section I do this :
spyOn(Serviceinstance, 'B').and.callFake(function(){
return true;
});
in my Test :
var result = Serviceinstance.A();
expect(result).toBeTrue();
Of course, the real code of B returns false.
My problem is that my test always fails. the function provided in the spy is never called by method A.
On the other hand, If I call B like this :
var result = Serviceinstance.B();
Then the function of the spy is called, and my test passes.
So should I modify my instance like this :
Serviceinstance.B = function(){return true;}
because Jasmine cannot mock a "second" level of the call stack ? (seems totally unlikely to me)
I am definitively missing something....

This is a code that works:
describe('Service test suite', function() {
it('should return true', function() {
var Serviceinstance = new Service();
spyOn(Serviceinstance, 'B').and.callFake(function() {
return true;
});
expect(Serviceinstance.A()).toBe(true);
})
});
https://jsfiddle.net/ronapelbaum/9moLhhbr/

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

How to mock a promise in Karma unit test called inside a function

I have the following function in my Angular controller and want to test, if the promise returns the expected result
function getName() {
var name = "";
nameService.getName().then(function (data) {
name = data.name;
});
return name;
}
How can I mock the promise call with fake data? I am not sure if I can use $httpBackend or $provide here? I tried this but it didn't work:
it("function getName should get the name from the nameService.getNameInfo function", function () {
var name = { name: "name1"};
spyOn(mockNameService, 'getNameInfo').and.callFake(function() {
return {
then: function(callback) {return callback(name);}
};
});
var result = myCtrl.getName();
expect(result).toEqual("name1");
});
Try using:
spyOn(mockNameService, 'getNameInfo').and.returns($q.when('dummyData'));
to mock your data.
Then you need to verify once it is resolved. So write:
expect(myCtrl.getName().then(function(name){
expect(name).toBe('dummyData');
}).toBeResolved();
The problem is not with your unit testing code, its an wrong implementation at all of the application code.
here:
function getName() {
var name = "";
nameService.getName().then(function (data) {
name = data.name;
});
return name; //it will return "" because the promise yet not resolved
}
In this code function getName will always return a empty string "" and it will never return the values you are assigning when the promise resolves name = data.name because promises are asynchronous, so by the time its resolves the function getName already returned the empty string to the caller!
So, in this case, refactoring the original code and fixed it there dhould be the first idea!
Actually your unit test codes identified the bug in your code, so its served already its original purpose, test case failing doesn't always meant that you have to fix it there, rather if your test cases are perfectly written against the logical expectation for all possible units/modules you need to think about why it is failing, looking at the actual code, and that is the actual purpose of writing unit test cases

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

What's wrong with this Angular code?

angular.module('events.services', [])
.factory('EventService', function($http, $cordovaSQLite) {
return {
test: function() {
return 'It Works!';
}
}
}
})
Controller
.controller('NearCtrl', function($scope, $http, $cordovaSQLite, EventService) {
var test = EventService.test;
console.log(test); // I expect 'It works' to be here, but returns 'function test();'
})
Why doesn't this return 'It Works!' ? Thanks a lot.
As per comments, and as per the JS language
In the following link
Calling functions
Defining a function does not execute it. Defining the function simply names the function and specifies what to do when the function is called. Calling the function actually performs the specified actions with the indicated parameters. For example, if you define the function square, you could call it as follows:
square(5);
As you can see, the function requires () to be executed.
function square(num){
return num
}
console.log(square);
=> function square(num)
console.log(square( 5 ));
=> 5
As you are using your factory,
console.log(EventService);
=> { test: function() { return 'It Works!'; }
In your scenario, your factory has returned an object with a property test that points to an anonymous function.
Simply calling EventService.test returns the anonymous function just as it did when we called console.log(square);. To utilize the returned function value you must also call it like so
EventService.test();
Continue to post questions as you see fit, but also remember to troubleshoot your code first, and if you still need to ask a question include all the steps you took to troubleshoot your problem :)

How to display multiple tests with Qunit

The code below has two functions being tested. The contents of these two functions is completely irrelevant. Below these two functions are two additional test functions of which each is testing one of the two previous functions.
The problem
The only output I get in the Qunit display is the results of the first test function which in this case is "add function". I would like to see both and any additional tests in the same output.
Am I missing some syntax that tells Qunit that I want to see the test results of both?
Thank you.
Code
function add(a,b){
return a+b;
};
var answer = add(2,2);
function mathy(a,b,callback){
return callback(a,b)
}
var mathFunc = mathy(2,2,add)
// Test one
test( "add function", function() {
ok(answer === 4);
});
// Test2
test( "callback function", function() {
ok(mathFunc === 4)
});
Use the Qunit autostart flag and the init() and start() methods to run the tests manually:
function add(a,b){
return a+b;
};
var answer = add(2,2);
function mathy(a,b,callback){
return callback(a,b)
}
var mathFunc = mathy(2,2,add)
QUnit.config.autostart = false;
QUnit.init();
QUnit.start();
// Test one
test( "add function", function() {
ok(answer === 4);
});
// Test2
test( "callback function", function() {
ok(mathFunc === 4)
});
References
Managing QUnit Test Suites with Async Module Dependencies | Ian Chan's Blog
Testing Oracle JET Applications

Categories