I have a javascript function like this:
var otherModule = require('../otherModule');
function myFn(req, res, next) {
otherModule.queryFunction()
.then(function(results) {
res.json(results);
})
.catch(function(err)) {
res.json({
err: err
});
});
}
In order to test myFn function I've mocked (with mockery) otherModule.queryFunction in my unit test so it returns some known results. In myFn unit test I want to test that res.json is being called. I know if I were testing otherModule.queryFunction I could accomplish that by returning the promise or by passing done argument to the spectation function. But i can't figure out how to make an asynchronous test if the asynchronous part is inside a function called by the function i'm testing.
I've tried this approach without success:
'use strict';
var chai = require('chai');
var mockery = require('mockery');
var expect = chai.expect;
var spies = require('chai-spies');
var myFn = require('path/to/myFn');
chai.use(spies);
describe('myFn tests', function (){
var otherModule;
var SOME_DATA = {data: 'hi'};
beforeEach(function (){
otherModule = {
queryFunction: function queryFunctionMock(){
var promise = new Promise(function(resolve, reject){
resolve(SOME_DATA);
});
return promise;
}
};
});
beforeEach(function (){
mockery.enable({
warnOnReplace: false,
useCleanCache: true
});
mockery.registerMock('../otherModule', otherModule);
});
afterEach(function (){
mockery.disable();
});
it('res.json should be called with otherModule.queryFunction results', function (){
req = chai.spy();
res = chai.spy.object(['json']);
next = chai.spy();
myFn(req, res, next);
expect(res.json).to.have.been.called();
});
});
I think the only thing wrong here, is that you need to move the require of your component under test, after you initialized mockery:
'use strict';
var chai = require('chai');
var mockery = require('mockery');
var expect = chai.expect;
var spies = require('chai-spies');
var myFn;
chai.use(spies);
describe('myFn tests', function (){
// [...]
beforeEach(function (){
mockery.enable({
warnOnReplace: false,
useCleanCache: true
});
mockery.registerMock('../otherModule', otherModule);
// now load the component:
myFn = require('path/to/myFn');
});
Related
I have the problem:
var async = require('async');
function a() {
async.series([b,c], function(err) {
console.log('Done');
});
};
function b(next) {
next();
};
function c(next) {
next();
};
var methods = {
a: a,
b: b,
c: c
};
And I am trying to write a test like so:
spyOn(methods.a);
methods.a();
expect(methods.b).toHaveBeenCalled();
expect(methods.c).toHaveBeenCalled();
However both b and c do not register as having been called. Any ideas how to properly test this behavior?
If you use spy on function or method then Jasmine will be look at this function for check call it. And called function under Jasmine Spy is not execute its code by default.
spyOn(methods, "a");
methods.a();
expect(methods.a).toHaveBeenCalled();
In your case, you need check async code execution. We can do it with done function:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 2000;
spyOn(methods, "b");
spyOn(methods, "с");
methods.a();
setTimeout(function(){
expect(methods.b).toHaveBeenCalled();
expect(methods.c).toHaveBeenCalled();
done();
}, MAX_ASYNC_DELAY );
});
It will work if in methods.a() you will use next:
function a() {
async.series([methods.b, methods.c], function(err) {
console.log('Done');
});
}
If such adjustment is not possible, you should rewrite the test case in the following:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 2000;
spyOn(window, "b");
spyOn(window, "с");
methods.a();
setTimeout(function(){
expect(b).toHaveBeenCalled();
expect(c).toHaveBeenCalled();
done();
}, MAX_ASYNC_DELAY );
});
Owen Ayres advises not to use setTimeout in the test case. But this is impossible in your case if you are using Jasmine. Because jasmine.DEFAULT_TIMEOUT_INTERVAL is timeout waiting for call done function.
Example, your async timeout is eqaul nearly 10000 ms and you set MAX_ASYNC_DELAY to 11000 ms. The test case will be marked as failed, because jasmine.DEFAULT_TIMEOUT_INTERVAL equal 5000 ms by default. That need use override this param:
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 12000; // ms to wait for done()
});
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 11000;
// test case from above
});
afterEach(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
if you use Jasmine version 2.2 and above you can write:
it("should support async execution", function(done) {
var MAX_ASYNC_DELAY = 11000;
// test case from above
}, 12000);
Avoid setTimeout in a unit test at all costs. Here is how you should test it in a readable, 'Triple A Testing' format. Using Jasmine's async done will ensure it waits for a certain length of time before failing if the function call is never made. If you want to customise this for this test case, you could do something like defined in my beforeEach below (but inside the test itself).
beforeEach(function() {
// these are not required, including to show you can have if desired
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; // ms to wait for done()
});
it('calls methods b and c when a is called', function (done) {
var a = spyOn(methods.a);
var b = spyOn(methods.b);
methods.a();
expect(a).toHaveBeenCalled();
expect(b).toHaveBeenCalled();
done();
});
afterEach(function() {
// could be inline of above test if not needed for multiple cases.
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
Do not use timeouts in the test. This is not a clean way of testing and should be avoided unless absolutely essential.
I have notice that unit testing in javascript and its frameworks is very painful. Many fail positive results. I.e
it('should call Event.create when all if ok', function () {
EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
done();
});
});
EventsPersistancyService:
var EventsPersistancyService = {
accept: function acceptService(msg) {
var worker_id = WorkerCacheService.get('some login');
var app_category = AppCategoryService.get('some');
Event.create('msg'); <------------ **first**
var p = Q.all([worker_id, app_category]).then(function () {
var content = msg.content.toString();
content = JSON.parse(content);
var tmp = {};
return Event.create('msg'); <------ **second**
});
return p;
}
}
In that example test pass but it shouldn't. What am I doing wrong?
For starters, you never defined the done callback in your callback to it. But for promises, it is better to return the promise in your test, mocha will wait for promises to resolve.
it('should call Event.create when all if ok', function () {
return EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
});
});
A working example with your done callback (note the done declaration as function argument):
it('should call Event.create when all if ok', function (done) {
EventsPersistancyService.accept(message).then(function () {
sinon.assert.calledOnce(s3);
done();
});
});
I have a nodejs library written using the async/await module. I try to consume it from a library which uses regular callbacks. Here is a sample code:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async (function() {
var resultA = await (Promise.promisify(bar));
return 111;
})
function bar(callback) {
setTimeout(callback, 2000)
}
function moo() {
var f = async.cps(foo)
f(function(err, res) {
console.log(res)
})
}
moo()
I expected console.log to print 111 but instead it prints:
{ _bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_progressHandler0: undefined,
_promise0: undefined,
_receiver0: undefined,
_settledValue: undefined }
btw if I inline the foo implementation in the "async.cps" line it works (but this is not an option since its an external library).
Any idea?
I've looked at the library your using, and by the look of it (there isn't much, and certainly no working samples), you're not using it correctly.
async(fn) will return a function that accepts some input values and upon execution will return a promise (Probably standard Promises/A+). Inside, it will call fn with the input parameters, and will resolve the returned promise when fn has returned.
async.cps(...) will return a function that accepts some input values and a node style callback function (function (err, res)) and upon execution will return a void (undefined). Inside, it will call fn with the input parameters, and will call the callback function when fn has returned with the appropriate values.
what your code does is create a function with async(fn), then pass this function to async.cps(..) as if you called async.cps(async(fn)), but that doesn't make any sense.
What you could do if you wanted to "convert" a promise to a node style callback function (unpromisifying!) using this library is this:
function moo() {
var f = async.cps(function() {
return await (foo())
})
f(function(err, res) {
console.log(res)
})
}
You double-asynced the foo function. Here are your options, depending on whether you can modify the declaration of foo or not:
Leave foo async, and create a function f that accepts a node-style callback using cps:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
var f = async.cps(function() {
return await(foo());
});
f(function(err, res) {
console.log(res);
});
}
moo();
Leave foo async, and use an async moo:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
var moo = async(function() {
try {
var res = await(foo());
console.log(res);
} catch (err) {
}
});
moo();
Make foo already cps at the declaration:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async.cps(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
foo(function(err, res) {
console.log(res);
});
}
moo();
I have created a promise using kriskowal/q module but when i try to use this it does not go into any function either happy path or error path.
here is my promise creation class
var Q = require('q');
var Test = function () {
};
Test.prototype = (function () {
var testt = function () {
var deferred = Q.defer();
var x = 5;
if (x === 5){
deferred.resolve('resolved');
}else{
deferred.error(new Error('error'));
}
return deferred.promise;
};
return {
testt : testt
}
}());
module.exports = Test;
and this is how i am going to use it
var Test = require('../src/js/test.js');
describe("Test", function () {
"use strict";
var test = null;
beforeEach(function () {
test = new Test();
});
it("should return the promise", function () {
test.testt().then(
function (a) {
console.log(a);
},
function (b) {
console.error(b);
}
);
});
});
since this is a jasmine test class if your not familiar with jasmine, what is inside 'it' function is the logic how i am using the promise. And the 'testt' is the function where i create the promise. for more clarification i have attached the entire code.
Issue : It does not print either a or b
Your it is finishing immediately, instead of after the promise's resolution/rejection.
it("should return the promise", function (done) {
test.testt().then(
function (a) {
console.log(a);
done();
},
function (b) {
console.error(b);
done();
}
);
});
See here for more info.
I am setting up tests for my application, and I wish to check a method was called x times using Sinon, my testing framework is Mocha.
How can I achieve this, below is the code I wish to test, I'm looking to ensure recursiveRequest is called x times by createClients.
Nodezilla.prototype.createClients = function(batched, i){
var self = this;
if(batched)
batchRequests();
if(batched == false && i < this.virtualUsers){
// set timeout to help prevent out of memory errors
setTimeout( function() {
self.createClients(false, i+1);
}, 0 );
}else{
this.recursiveRequest();
}
};
Nodezilla.prototype.recursiveRequest = function(){
var self = this;
self.hrtime = process.hrtime();
if(!this.halt){
self.reqMade++;
this.http.get(this.options, function(resp){
resp.on('data', function(){})
.on("end", function(){
self.onSuccess();
});
}).on("error", function(e){
self.onError();
});
}
};
Attempted test but no avail as callCount returns 0.
var assert = require('assert'),
sinon = require('sinon'),
nz = require('../Nodezilla'),
nt = new nz("localhost", 10);
describe('Nodezilla', function(){
describe('createClients', function(){
before(function() {
sinon.spy(nt, "recursiveRequest");
});
it('should call recursiveRequest() 10 times', function(){
nt.createClients(false, 0);
assert(nt.recursiveRequest.callCount);
});
});
});
createClients seems to be an async request, without a callback/promise.
This means your test is evaluated immediately, and does not wait for results.
I'd suggest to re-write the function with a callback or promise so you are able to act on the event of processing completed, and then this should work:
var assert = require('assert'),
sinon = require('sinon'),
nz = require('../Nodezilla'),
nt = new nz("localhost", 1);
describe('Nodezilla', function () {
describe('createClients', function () {
it('should call recursiveRequest() 10 times', function (itCallback) {
// Moved into the test:
sinon.spy(nt, "recursiveRequest");
nt.createClients(false, 0, function(){
// Needs to wait for action to actually be called:
assert(nt.recursiveRequest.callCount == 10);
// Now that the test is actually finished, end it:
itCallback();
});
});
});
});
Skipping the before statement, as this might interfere with scopes, sinon.spy being synchronous can be called inside the test.
Also note I have introduced a callback in this statement:
it('should call recursiveRequest() 10 times', function (callback) {
to hold the test from finishing before the inner callback is called.
Edit:
As for adding the callbacks, I'm not sure what does batchRequests() does, but go like that:
Nodezilla.prototype.createClients = function (batched, i, cb) {
var self = this;
if (batched)
batchRequests();
if (batched == false && i < this.virtualUsers) {
// set timeout to help prevent out of memory errors
setTimeout(function () {
self.createClients(false, i + 1, cb);
}, 0);
} else {
this.recursiveRequest(cb);
}
};
And then:
Nodezilla.prototype.recursiveRequest = function (cb) {
var self = this;
self.hrtime = process.hrtime();
if (!this.halt) {
self.reqMade++;
this.http.get(this.options, function (resp) {
resp.on('data', function () {
})
.on("end", function () {
self.onSuccess();
cb();
});
}).on("error", function (e) {
self.onError();
cb();
});
} else {
// I assume you are doing nothing in this case, so just call the callback:
cb();
}
};
Also note you can use the callback for error handling.