Mocha sinon.spy always showing function call 0 times - unit-testing

I am new to mocha/chai. I am trying to write the unit test case for following scenario. I want to test whether "callchildfunc" and "childfunc2" is called or not upon calling "parent()" function.
I have read the fundamental and what I understood is if you are spying on any function then just put assert on that function to check if that function is called or not. Means in above script file If i will spy on "childfunc2" and "callchildfunc" function then I don't need to call here in test file since it is already called in script file under parent function. Please correct my understanding if I am wrong.
This is my script.js file
// script.js
function childfunc2(){
console.log("child function without return");
}
function callchildfunc(var1, var2){
return var1 + var2;
}
function parent(x){
var getreturnval = callchildfunc(x, 1);
console.log(getreturnval);
childfunc2();
}
This is my test file.
//scenario 1
describe('Test for parent() function ', function(){
it('should make parent call ', function(){
var spy1 = sinon.spy(window, 'callchildfunc');
var spy2 = sinon.spy(window, 'childfunc2');
parent(2);
expect(spy1).to.have.been.called();
expect(spy2).to.have.been.called();
// or
sinon.assert.calledOnce(spy1);
sinon.assert.calledOnce(spy1);
});
});
After running the test always I am getting this error.
AssertError: expected childfunc2 to be called once but was called 0 times
Also If I change the test file and call the spy function then it will work.
var spy1 = sinon.spy(window, 'callchildfunc');
var spy2 = sinon.spy(window, 'childfunc2');
parent(2);
// After addding these below 2 lines.
window.childfunc2();
window.callchildfunc();
Any help?

// Script.js
module.exports= {
childfunc2:function(){
console.log("child function without return");
},
callchildfunc:function(var1, var2){
return var1 + var2;
},
parent:function(x){
var getreturnval = this.callchildfunc(x, 1);
console.log(getreturnval);
this.childfunc2();
}
};
// Test.js
var sinon= require('sinon'), expect=require('chai').expect
var r= require('./functests')
describe('Test for parent() function ', function(){
it('should make parent call ', function(){
var spy1 = sinon.spy(r, 'callchildfunc');
var spy2 = sinon.spy(r, 'childfunc2');
r.parent(2);
// expect(spy1).to.have.been.called();
// expect(spy2).to.have.been.called();
// or
sinon.assert.calledOnce(spy1);
sinon.assert.calledOnce(spy1);
});
});
// Screenshot

Related

Postman API Tests

I have a response body like
{
"agreementId": "agreement900",
"Status": "ONHOLD"
}
The value of the status can be one of
['PAID','CANCELLED','COOLINGOFF','ONHOLD','COOLINGOFF','PAID']
I need to write a generic test to verify that the body.Status is always among the specified array.
I tried something like this
var data = ['PAID','CANCELLED','COOLINGOFF','ONHOLD','COOLINGOFF','PAID'];
pm.test("Verify Body value", function () {
let testResult = data.find((each)=>{
pm.expect(each.payoutStatus).to.equal(jsonData.payoutStatus)
});
});
But received the following error: Verify Body value | AssertionError: expected undefined to equal 'ONHOLD'
Deepak, welcome to SO
I am not sure about edge cases nor performance, but this can be a way of achieving it:
var myStatus = pm.response.json().Status;
var myEnum = ['Pig','Chicken','Cow'];
pm.test("Status belongs to the ENUMs", function () {
pm.expect(myEnum).to.include(myStatus);
});

Yeoman testing times out anywhere but locally

I have some testing with the following structure:
describe('yeoman:subyeoman', function () {
before(function (done) {
helpers.run(path)
.inTmpDir(function (dir) {
** some file copying **
})
.withOptions({
'option': options
})
.withArguments(argumentsJson)
.on('ready', function (generator) {
generator.conflicter.force = true;
var html = "some html";
var dir = generator.destinationPath('app');
var file = generator.destinationPath('app/file.html');
if (!fs.existsSync(dir)) fs.mkDir(dir);
fs.writeFile(file, html);
})
.on('end', function () {
fse.removeSync(somePath);
done();
});
});
it('.....');
});
The on('ready') piece does its work both locally and inside the docker container, but inside the container never calls generator.run() and throws the following error:
Error: timeout of 20000ms exceeded. Ensure the done() callback is being called in this test.
I've tried changing the timeout and doing it the async way but the output its still the same.
Any help will be appreciated .
This seems to happen if you have an error in your code that doesn't bubble up with testing. Check any manipulation to the this context especially.

How to test nested callbacks with Mocha/Sinon?

What is the/one correct way to test this piece of JavaScript code using, e.g, Mocha/Sinon:
var App = function(endPoint, successCallback) {
var channel = new WebSocket(endPoint);
channel.onopen = function(ev) {
successCallback();
};
};
I'm thinking of something like this:
describe('App', function() {
it('test should create instance and call success', function(done) {
var app = new App('ws://foo.bar:123/', done);
var stub = sinon.stub(app, 'channel');
stub.yield('onopen');
});
});
Apparently, that does not work as channel is not accessible from outside the constructor. How would you test this?
Why not create a factory for Websocket such as:
var myApp = {
createWebsocket: function () {
return new Websocket;
}
};
This would make spying on the myApp.createWebsocket return value channel very easy:
sinon.spy(myApp, 'createWebsocket);
var channel = myApp.createWebsocket.firstCall.returnValue;
var stub = sinon.stub(channel, 'onopen');
stub.yield('onopen');
// Clean up
myApp.createWebsocket.restore();

Does Jasmine's spyOn() allow the spied on function to be executed?

Does Jasmine's spyOn() method allow the spied on function to be executed, or does it, kind of - intercept the invocation when the spied method is (about to get) invoked, and returns true.
PS: Could anyone point me to the explanation of spyOn()'s inner workings?
Spy :
A spy can pretend to be a function or an object that you can use while writing unit test code to examine behavior of functions/objects
var Person = function() {};
Dictionary.prototype.FirstName = function() {
return "My FirstName";
};
Dictionary.prototype.LastName = function() {
return "My LastName";
};
Person.prototype.MyName = function() {
return FirstName() + " " + LastName();
};
Person.prototype.MyLocation = function() {
Return ”some location”;
};
describe("Person", function() {
it('uses First Name and Last Name for MyName', function() {
var person = new Person;
spyOn(person , "FirstName");
spyOn(person, "LastName");
person.MyName();
expect(person.FirstName).toHaveBeenCalled();
expect(person.LastName).toHaveBeenCalled();
});
});
Through SpyOn you can know whether some function has been / has not been called
expect(person. MyLocation).not.toHaveBeenCalled();
You can ensure that a spy always returns a given value and test it
spyOn(person, " MyName ").andReturn("My FirstNameMy LasttName ");
var result = person.MyName();
expect(result).toEqual("My FirstName My LasttName ");
Spies can call through to a fake function
it("can call a fake function", function() {
var fakeFun = function() {
alert("I am a spy!”);
return "hello";
};
var person = new person();
spyOn(person, "MyName").andCallFake(fakeFun);
person. MyName (); // alert
})
You can even create a NEW spy function or object and make use of it
it("can have a spy function", function() {
var person = new Person();
person.StreetAddress = jasmine.createSpy("Some Address");
person. StreetAddress ();
expect(person. StreetAddress).toHaveBeenCalled();
});
It just creates a mock(spy) object and injects it to your tested code.
It has three main purposes:
Testing your code if it calls spy: toHaveBeenCalled
Testing your code if it calls with appropriate parameters: toHaveBeenCalledWith
Testing your code for different return values from spy: and.callThrough

How do I mock an Angular service using jasmine?

This may be a duplicate but I have looked at a lot of other questions here and they usually miss what I am looking for in some way. They mostly talk about a service they created themselves. That I can do and have done. I am trying to override what angular is injecting with my mock. I thought it would be the same but for some reason when I step through the code it is always the angular $cookieStore and not my mock.
I have very limited experience with jasmine and angularjs. I come from a C# background. I usually write unit tests moq (mocking framework for C#). I am use to seeing something like this
[TestClass]
public PageControllerTests
{
private Mock<ICookieStore> mockCookieStore;
private PageController controller;
[TestInitialize]
public void SetUp()
{
mockCookieStore = new Mock<ICookieStore>();
controller = new PageController(mockCookieStore.Object);
}
[TestMethod]
public void GetsCarsFromCookieStore()
{
// Arrange
mockCookieStore.Setup(cs => cs.Get("cars"))
.Return(0);
// Act
controller.SomeMethod();
// Assert
mockCookieStore.VerifyAll();
}
}
I want mock the $cookieStore service which I use in one of my controllers.
app.controller('PageController', ['$scope', '$cookieStore', function($scope, $cookieStore) {
$scope.cars = $cookieStore.get('cars');
if($scope.cars == 0) {
// Do other logic here
.
}
$scope.foo = function() {
.
.
}
}]);
I want to make sure that the $cookieStore.get method is invoked with a 'garage' argument. I also want to be able to control what it gives back. I want it to give back 0 and then my controller must do some other logic.
Here is my test.
describe('Controller: PageController', function () {
var controller,
scope,
cookieStoreSpy;
beforeEach(function () {
cookieStoreSpy = jasmine.createSpyObj('CookieStore', ['get']);
cookieStoreSpy.get.andReturn(function(key) {
switch (key) {
case 'cars':
return 0;
case 'bikes':
return 1;
case 'garage':
return { cars: 0, bikes: 1 };
}
});
module(function($provide) {
$provide.value('$cookieStore', cookieStoreSpy);
});
module('App');
});
beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
scope = $rootScope.$new();
controller = $controller;
}));
it('Gets car from cookie', function () {
controller('PageController', { $scope: scope });
expect(cookieStoreSpy.get).toHaveBeenCalledWith('cars');
});
});
This is a solution for the discussion we had in my previous answer.
In my controller I'm using $location.path and $location.search. So to overwrite the $location with my mock I did:
locationMock = jasmine.createSpyObj('location', ['path', 'search']);
locationMock.location = "";
locationMock.path.andCallFake(function(path) {
console.log("### Using location set");
if (typeof path != "undefined") {
console.log("### Setting location: " + path);
this.location = path;
}
return this.location;
});
locationMock.search.andCallFake(function(query) {
console.log("### Using location search mock");
if (typeof query != "undefined") {
console.log("### Setting search location: " + JSON.stringify(query));
this.location = JSON.stringify(query);
}
return this.location;
});
module(function($provide) {
$provide.value('$location', locationMock);
});
I didn't have to inject anything in the $controller. It just worked. Look at the logs:
LOG: '### Using location set'
LOG: '### Setting location: /test'
LOG: '### Using location search mock'
LOG: '### Setting search location: {"limit":"50","q":"ani","tags":[1,2],"category_id":5}'
If you want to check the arguments, spy on the method
// declare the cookieStoreMock globally
var cookieStoreMock;
beforeEach(function() {
cookieStoreMock = {};
cookieStoreMock.get = jasmine.createSpy("cookieStore.get() spy").andCallFake(function(key) {
switch (key) {
case 'cars':
return 0;
case 'bikes':
return 1;
case 'garage':
return {
cars: 0,
bikes: 1
};
}
});
module(function($provide) {
$provide.value('cookieStore', cookieStoreMock);
});
});
And then to test the argument do
expect(searchServiceMock.search).toHaveBeenCalledWith('cars');
Here is an example https://github.com/lucassus/angular-seed/blob/81d820d06e1d00d3bae34b456c0655baa79e51f2/test/unit/controllers/products/index_ctrl_spec.coffee#L3 it's coffeescript code with mocha + sinon.js but the idea is the same.
Basically with the following code snippet you could load a module and substitute its services:
beforeEach(module("myModule", function($provide) {
var stub = xxx; //... create a stub here
$provide.value("myService", stub);
}));
Later in the spec you could inject this stubbed service and do assertions:
it("does something magical", inject(function(myService) {
subject.foo();
expect(myService).toHaveBeenCalledWith("bar");
}));
More details and tips about mocking and testing you could find in this excellent blog post: http://www.yearofmoo.com/2013/09/advanced-testing-and-debugging-in-angularjs.html
Why mock cookieStore when you may use it directly without modification? The code below is a partial unit test for a controller which uses $cookieStore to put and get cookies. If your controller has a method known as "setACookie" that uses $cookieStore.put('cookieName', cookieValue) ... then the test should be able to read the value that was set.
describe('My controller', function() {
var $cookieStore;
describe('MySpecificController', function() {
beforeEach(inject(function(_$httpBackend_, $controller, _$cookieStore_) {
$cookieStore = _$cookieStore_;
// [...] unrelated to cookieStore
}));
it('should be able to reference cookies now', function () {
scope.setACookie();
expect($cookieStore.get('myCookieName')).toBe('setToSomething');
});
});