I can get tests to run in Intern, but I am struggling with getting spies to work. I'm trying to integrate sinon so I can get spies. Here is a sample test file:
define([
'intern!bdd',
//'intern/chai!expect',
//'intern/order!node_modules/intern/chai',
// 'intern/order!node_modules/chai/lib/chai',
// 'intern/order!node_modules/sinon/lib/sinon',
// 'intern/order!node_modules/sinon-chai/lib/sinon-chai',
'intern/order!node_modules/sinon/lib/sinon',
'intern/order!node_modules/sinon/lib/sinon/spy',
'intern/order!node_modules/sinon/lib/sinon/call',
'intern/order!node_modules/sinon/lib/sinon/behavior',
'intern/order!node_modules/sinon/lib/sinon/stub',
'intern/order!node_modules/sinon/lib/sinon/mock',
'intern/order!node_modules/sinon/lib/sinon/collection',
'intern/order!node_modules/sinon/lib/sinon/assert',
'intern/order!node_modules/sinon/lib/sinon/sandbox',
'intern/order!node_modules/sinon/lib/sinon/test',
'intern/order!node_modules/sinon/lib/sinon/test_case',
'intern/order!node_modules/sinon/lib/sinon/match',
'intern/order!vendor/src/angular/angular',
'intern/order!vendor/src/angular-mocks/angular-mocks',
'intern/order!src/common/modules/error_handling/error_handling'
], function (bdd, sinon, spy, call, behavior, stub, mock, collection, assert, sandbox, test, test_case, match) {
with (bdd) {
sinon.spy = spy;
sinon.call = call;
sinon.behavior = behavior;
sinon.stub = stub;
sinon.mock = mock;
sinon.collection = collection;
sinon.assert = assert;
sinon.sandbox = sandbox;
sinon.test = test;
sinon.test_case = test_case;
sinon.match = match;
describe('Error handler module', function () {
var test, scope, ctrl, error_handler, log;
function inject (fn) {
return function() {
angular.injector(['ng', 'ngMock', 'error_handling']).invoke(fn);
}
}
beforeEach(inject(function($log){
log = $log;
}));
it('should be an object', function(){
//expect(log).to.be.an('object');
});
it('should call console.trace with the string test', function(){
var spy = sinon.spy(console.trace);
//expect(sinon.spy).to.be.ok;
//log.debug('test');
console.trace('test');
//spy.should.be.ok;
spy.should.have.been.calledWith('test');
//chai.expect(spy).to.have.been.called.with('test');
});
});
}
});
I based it off of https://github.com/theintern/intern/blob/sinon/sinon.js
But I get this error failure:
>> 1/6 tests failed
Warning: FAIL: main - Error handler module - should log nothing when the logging mode is off (1ms)
TypeError: 'undefined' is not an object (evaluating 'spy.should.have')
at </Users/evanvandegriff/Documents/work/nomi_v2/nomi_v2/web/src/common/modules/error_handling/error_handling.test.js:67>
at <__intern/lib/Test.js:169>
at <__intern/lib/Suite.js:237>
at <__intern/node_modules/dojo/Deferred.js:37>
at <__intern/node_modules/dojo/Deferred.js:258>
at runTest <__intern/lib/Suite.js:241>
at <__intern/lib/Suite.js:249
Anyone have any ideas why this isn't working?
As #Fordio indicated, the syntax you're trying to use is part of Sinon-Chai, not vanilla Sinon.js. You'll need to require that package as a dependency, or use the native Sinon.js assertions.
Related
Just starting with Sinon, Mocha, and Chai JS. After upgrading UnderscoreJS version from 1.4.4 to 1.9.1, I had to update how my project was using template function.
Previously, _.template function was used in this way -
var myTemplate = _.template("<p><%= name %></p>", {name: 'Joe Doe'});
New Way,
// `myTemplate` here is a function!
var myTemplate = _.template("<p><%= name %></p>");
// Now let's pass in the data for the template.
myTemplate({name: 'Joe Doe'}); // it returns: "<p>Joe Doe</p>"
However, this change caused a lot of the existing test cases to fail. Below mentioned is one of the test cases I need help with -
const sinonVar = require('sinon');
describe('testVar', function() {
var sanboxVar;
var ss = requirejs('Path to JS library');
var testVar;
beforeEach(function(done) {
console.log("Not Called"); // Never printed on console
done();
sanboxVar = sinonVar.sanbox.create();
});
it('some text here', function() {
console.log("sanboxVar: " + sanboxVar); //Printed on console as 'undefined'
ss.id = sanboxVar.stub();
});
});
On "npm test", I see the error -
testVar
some text here:
TypeError: Cannot read property 'stub' of undefined
at Context.<anonymous> (testPage.js) - "This is pointing to sanboxVar not defined"
I think for some reason, beforeEach method is not getting called and hence the Sandoval variable is not getting initiated.
Any help would be appreciated.
Suppose I have a JavaScript code:
function modifiesLocalStorage() {
var someBoolean = false;
if(localStorage.getItem('someKey') === 'true'){
localStorage.removeItem('someKey');
someBoolean = true;
}
return someBoolean;
}
Then I have a jasmine test to test this method:
it('should return true', function(){
spyOn(localStorage, 'removeItem');
spyOn(localStorage, 'getItem').and.returnValue('true');
var returnValue = modifiesLocalStorage();
expect(localStorage.getItem).toHaveBeenCalled(); //Error in this line
expect(returnValue).toBeTruthy();
});
while executing this test I am getting following error:
Error: <toHaveBeenCalled> : Expected a spy, but got Function.
What is this error and how do I fix it?
I am using Firefox 45.9.0 browser in headless mode to run the tests.
As per this question's answer:
Expected a spy, but got Function
We need to get into the actual method, which in this case is on the proto.
if I modify my tests like below, the test passes:
it('should return true', function(){
spyOn(localStorage.__proto__, 'removeItem');
spyOn(localStorage.__proto__, 'getItem').and.returnValue('true');
var returnValue = modifiesLocalStorage();
expect(localStorage.__proto__.getItem).toHaveBeenCalled();
expect(returnValue).toBeTruthy();
});
Since __proto__ is deprecated we can also use Object.getPrototypeOf(localStorage) to get the prototype of the localStorage object
I have an ngResourceMockFactory which looks like this:
(function() {
'use strict';
angular.module('app')
.factory('NgResourceMock', ngResourceMockFactory)
;
ngResourceMockFactory.$inject = [];
function ngResourceMockFactory() {
function NgResourceMock() {
var context = this;
context.$promise.then = function() {
context.prototype.$promise.then.apply(context, arguments);
};
context.$promise.finally = function() {
context.prototype.$promise.finally.apply(context, arguments);
};
}
NgResourceMock.prototype.$promise = {
then: function(onSuccess, onError) {
this.$promise.onSuccess = onSuccess;
this.$promise.onError = onError;
},
finally: function(onComplete) {
this.$promise.onComplete = onComplete;
}
};
return NgResourceMock;
}
})();
I inject this into my tests in a beforeEach like so:
beforeEach(inject(function(NgResourceMock) {
ngResourceMock = new NgResourceMock();
}));
then I use it like this:
describe('initiateWorkflow function', function() {
beforeEach(function() {
vm.player = {id: 123};
spyOn(dataService, 'initiateWorkflow').and.returnValue(ngResourceMock);
vm.initiateWorkflow();
});
it('should call dataService.initiateWorkflow', function() {
expect(dataService.initiateWorkflow).toHaveBeenCalledWith({playerId: vm.player.id}, {});
});
});
but I keep seeing the following error:
TypeError: 'undefined' is not an object (evaluating 'context.prototype.$promise')
This leads me to believe that something is wrong with my ngResourceMockFactory, but I'm not sure what it is.
Don't know if this can be of any help, but if you are trying to evaluate asynchronous operations in your tests, you may want to use the done() method in Jasmine.
As per their documentation:
beforeEach(function(done) {
setTimeout(function() {
value = 0;
done();
}, 1);
});
by passing done as a parameter of the beforeEach callback, any test run after the before each will wait until the done() function has been called.
Source: Jasmine (Asynchronous Support section).
Hope this helps.
Here is the solution to your problem.
The error TypeError: 'undefined' is not an object (evaluating 'context.prototype.$promise') is caused when you try to invoke the promise object before invoking the function into which it is defined or into which your parent function is defined.
Here the returnValue(ngResourceMock) is directly calling into the function without the context and parameters need to be defined.
Therefore you can try to add another beforeEach statement like
beforeEach(angular.mock.module(app));
to load your app module
Here may be the same concept related to your problem another link here.
Hope it may help you a bit.
I am testing a function. That function has a call to an external module which makes my test fail:
element.funcCall();
Where the function looks like this:
function funcCall() {
external.a.b.c.doSomething();
}
It fails on: undefined is not an object (evaluating 'external.a.b.c.doSomething')
How can I stub or fake this so the call is not really make. I do not need it's functionality for this test.
Here's how I do this kind of thing:
var element = require('element'),
external = require('external'),
sinon = require('sinon'),
expect = require('chai').expect;
describe('element.funcCall()', function() {
before(function() {
this.doSomethingStub = sinon.stub(external.a.b.c, 'doSomething');
});
it('should do something external', function() {
element.funcCall();
expect(this.doSomethingStub.called).to.be.true;
});
after(function() {
this.doSomethingStub.restore();
});
});
Here is how I ended up solving this. Since I did not care about that external function being executed, I faked it like so:
var func = function() {};
external =
{ a:
{ b:
{ c:
{doSomething: func}
}
}
}
...
element.funcCall();
expect.....
This was the internal function call was redirected to en empty function and I could test the rest of the method
I m actually using a micro framework created by my society in which we use Mongoose.
To manage the mongoose object, we created a modelfactory, that returns us a model corresponding to the mongoose name object.
Actually, I m working on an authentication service in which I inject this modelfactory.
I need to unit test it with mocha and sinonjs, but I m a bit lost...
This is my authentication Service method that I want to test :
class AuthenticationService extends Service
constructor: (modelFactory)->
super(modelFactory)
#authorizedClientIds = [
"123456"
"toto"
]
#OAuthAccessTokensModel = #modelFactory.getSchema('OAuthAccessTokens')
#OAuthClientsModel = #modelFactory.getSchema('OAuthClients')
#OAuthUsersModel = #modelFactory.getSchema('OAuthUsers')
#OAuthRefreshTokensModel = #modelFactory.getSchema('OAuthRefreshTokens')
## Get an access token from the bearer token ##
getAccessToken: (bearerToken, callback)->
#OAuthAccessTokensModel.findOne({accessToken: bearerToken}, callback)
module.exports = AuthenticationService
I want to test the getAccessToken method, but I have clearly no idea how to make it work...
I've tried to make something like :
describe("Authentication Service", function () {
var service;
before(function () {
ModelFactory = use('/app/core/config/database/ModelFactory');
var mock = sinon.mock(ModelFactory.getFactoryInstance([]));
mock.expects("getSchema").withArgs("user").return({name:'user',getName:function(){}});
service = new AuthenticationService(mock);
});
describe("getAccessToken", function () {
it('should return-1 when the value is not present', function () {
var proxy = once(service.getAccessToken());
mock.verify();
});
});
});
How should I do to test it correctly ?
EDIT :
I've tried something, but it seems weird to test because I propose the result to compare, but the result expected too.. So I could never fail the test :x...
describe("Authentication Service", function () {
var service;
before(function () {
ModelFactory = use('/app/core/config/database/ModelFactory');
var factory = new ModelFactory([]);
sinon.stub(factory, "getSchema").returns({findOne: sinon.stub().returns()});
service = new AuthenticationService(factory);
});
describe("getAccessToken", function () {
it('Check if the access token correspond to a database entry', function () {
stubResult = {token: '123456'};
service.getAccessToken = sinon.stub().withArgs('1234').returns(undefined);
assert.equal(service.getAccessToken(), undefined);
});
});
});
Some help ?
Thanks for advance
The Unit test should test something that is not mocked/stubbed.
When you have a difficult method handleUnknownToken() this function can call your Authentication Service. The assert() should verify that the handling of the 'undefined' works as expected.
In other words: When you want to unit test f(x) = g()+h() +j(); you can test the correct implementation of g() by stubbing h() and j(), test h() by stubbing g() and j() and test j() by stubbing g() and h().
EDIT: The explanation above is abstract, since I do not know Mongoose/Mocha/Sinonjs. Beneath I'll try to focus on the case described.
When your service getAccessToken() is completely stubbed, the next tests
will succeed when your stub definition is correct:
testUnknown() {
constant UKNOWN_ITEM='1234';
assert.equal(service.getAccessToken(UNKNOWN_ITEM), undefined);
}
testTimeout() {
constant DIFFICULT_ITEM='1235';
assert.equal(service.getAccessToken(DIFFICULT_ITEM), STATUS_TIMEOUT);
}
testRevoked() {
constant REVOKED_ITEM='1236';
assert.equal(service.getAccessToken(REVOKED_ITEM), STATUS_DENIED);
}
testActive() {
constant ACTIVE_ITEM='1237';
assert.equal(service.getAccessToken(ACTIVE_ITEM), STATUS_OK);
}
Your test must include some logic you don't stub.
Waht is the code around calling getAccessToken()? Something like a function
isTokenOK(), that will look at the status and retry 5 times after a timeout?
With the stubs implemented for the above test you can test the boolean function isTokenOK() with
testUnknown() {
assertFalse(isTokenOK(UNKNOWN_ITEM));
}
testTimeout() {
assertFalse(isTokenOK(DIFFICULT_ITEM));
}
testRevoked() {
assertFalse(isTokenOK(REVOKED_ITEM));
}
testActive() {
assertTrue(isTokenOK(ACTIVE_ITEM));
}
And now, when somebody changes the implementation of isTokenOK(), your unit test can fail. When the unit test is failing, you must look who is right.
Maybe a token that has been revoked can be used for authentication the first 10 minutes after revocation and isTokenOK(REVOKED_ITEM) should be true.
Oh well, than you must add a new test for REVOKED_ITEM_YESTERDAY.