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();
});
});
Related
Pulling my hair out here trying to understand the infuriating nuances of Javascript. Hopefully some JS guru can take a gander, point and go, "well, there's yer problem...".
Here's a slimmed down sample of the problem:
var Parent = (function () {
var func1 = function () {
func2(function (res) {
console.log(res);
});
};
var func2 = function (callback) {
callback('abc');
};
return {
init: function () {
func1();
func2();
}
};
})();
Call with Parent.init();
This fails with the error:
Uncaught TypeError: callback is not a function
at check2 (<anonymous>:9:9)
at Object.init (<anonymous>:15:13)
at <anonymous>:1:8
What's getting me, is that if I comment out the enclosing code, like so, then it works as expected:
// var Parent = (function () {
var func1 = function () {
func2(function (res) {
console.log(res);
});
};
var func2 = function (callback) {
callback('abc');
};
// return {
// init: function () {
// func1();
// func2();
// }
// };
// })();
...and call with func1();
Result:
abc
What am I missing?
Thanks
In your version, you're calling func2() without specifying the callback function, which is a required argument. In your second example (with init commented out), you're correctly specifying the callback function in func2(function (res) { ... });.
Is the below snippet something you're looking for?
const Parent = (function () {
const func1 = function () {
func2(function (res) {
console.log(res);
});
}
const func2 = function (callback) {
callback('abc'); // this is passing 'abc' to line 3 of this snippet
}
return {
init: function () {
func1();
// func2(); // you don't want to call "func2" here, as "func1" calls it
// Or you could run:
func2(function (res) {
console.log(res);
});
// But this makes "func1" redundant
}
};
});
Parent().init();
// Output
abc
You have to pass callback parameter into func2 inside init. something like this.
init: function () {
func1();
func2(function (res) {
console.log(res);
});
}
From a comment on the question:
I just want to know why it works in the one sample, but not the other.
Because in one example you pass an argument to func2 and in the other you don't. Look at the working version:
func2(function (res) {
console.log(res);
});
vs. the non-working version:
func2();
The difference is that the first one passes a function which gets invoked as callback('abc'); whereas the second one passes nothing, so the attempt to invoke the non-existant callback function fails.
As an aside, in your non-working example you call func2 twice, once with the callback and once without. So it both "works" and "fails" in that case.
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');
});
I want to write a library in javascript that can run the code like this:
seq.next(function(done){
setTimeout(done,3000);
}).next(function(done){
setTimeout(function(){
console.log("hello");
done();
},4000);
}).end(); //.next morever
Actually I want to write a library that can excecute asynchronous functions in order(sequentially). Each asynchronous function should run the "done" function on its end.
Could anyone please help me. Thanks very much!
The library is:
var seq = (function () {
var myarray = [];
var next = function (fn) {
myarray.push({
fn: fn
});
// Return the instance for chaining
return this;
};
var end = function () {
var allFns = myarray;
(function recursive(index) {
var currentItem = allFns[index];
// If end of queue, break
if (!currentItem)
return;
currentItem.fn.call(this, function () {
// Splice off this function from the main Queue
myarray.splice(myarray.indexOf(currentItem), 1);
// Call the next function
recursive(index);
});
}(0));
return this;
}
return {
next: next,
end: end
};
}());
And the use of this library is sth like this:
seq.next(function (done) {
setTimeout(done, 4000);
}).next(function (done) {
console.log("hello");
done();
}).next(function (done) {
setTimeout(function () {
console.log('World!');
done();
}, 3000);
}).next(function (done) {
setTimeout(function () {
console.log("OK");
done();
}, 2000);
}).end();
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.