Suppose you have the following JS function:
function YourProxy($orm, $usr) {
this.addToDB = function(obj) {
/* Do some validation on obj */
return function(callback){
var oo = $orm.createNew(obj);
oo.save(options, function(err,ok){
if(err) callback(err);
callback(null,ok);
}
}
}
}
which you can use on node.js with ES6 generators to wait for that operation to happen with something like:
function *(){
var yourProxy = new YourProxy();
try {
var result = yield yourProxy.addToDB(anObject);
} catch(e) {
/* Something went wrong sync. Here you have err from save's callback */
}
/* result contains ok, the one from save's callback */
}
To test that I've done something like this, using mocha and sinon (and mocha-sinon):
describe('addToDB', function(){
it('adds the object to the db', function(){
var callback = sinon.spy();
myProxy.addToDB(anObject)(callback);
expect( callback ).to.be.calledOnce;
});
});
but all I got is that the callback is never called because addToDB() exits before the save's callback gets called.
How would you test that?
Try using co-mocha and yield the generator as you did it in your example.
describe('addToDB', function(){
it('adds the object to the db', function* (){
var callback = sinon.spy();
yield myProxy.addToDB(anObject)(callback);
expect( callback ).to.be.calledOnce;
});
});
Related
I have just started using Bluebird's Promise.coroutine which is a promise version of Generator functions from ES6.
Everything works fine when I create a function and put it in a variable. Like:
let success = Promise.coroutine(function* (_context) {
...
});
exports.success = Promise.coroutine(function* (_context) {
...
});
But when I try to create an standalone function. Like:
Promise.coroutine(function *success() {
...
});
It never defines a function and I get the error:
success is not defined
How do I access an standalone generator function? or more straight forward, how to create it?
Edit:
I am using validatejs, it requires success and error functions for async validations:
exports.create = function (req, res) {
var constraints = {
...
}
validate.async(req, constraints).then(Promise.coroutine(success), Promise.coroutine(error));
function success() { //generator
}
function error(e) { //generator
}
}
You can define a generator function as shown below.
function* functionName([param[, param[, ... param]]]) {
statements..
}
Please note that symbol * is with word function and not the functionname. The declaration function keyword followed by an asterisk defines a generator function.
Update1: Usage with the Promise.coroutine method. In javascript, function are first class citizen and hence can be passed as an parameter. So, you can replace the function expression with the functionname.
Promise.coroutine(functionName);
Your success() function doesn't have to be named because you are actualyy not calling that, but calling the coroutine Promise. See the example below. You should assign your coroutine to whatever you are trying to call it from, and then yield a Promise for your delayed processing (whatever that may be). Then you need to call the coroutine that will take care of returning the promise.
var Promise = require("bluebird");
function Test() {
}
Test.prototype.foo = Promise.coroutine(function* success() {
console.log("Called success")
var i = 0;
while (i < 3) {
console.log("Waiting and Yield " + i++);
yield Promise.delay(1000);
}
console.log("Test " + i);
});
var a = new Test();
a.foo();
console.log("Done!");
Then you will get this output :
>node index.js
Called success
Waiting and Yield 0
Done!
Waiting and Yield 1
Waiting and Yield 2
Test 3
I have a function:
var inRendering = false;
function render() {
if (inRendering) {
requestAnimationFrame(render);
} else {
inRendering = true;
requestAnimationFrame(function () {
longAction();
inRendering = false;
});
}
}
I have to unit-test it. To test a situation of concurrent call of render.
Help me, please? Is such concurrent call ever possible in JavaScript? Thanks.
P.S. I wrote a test which obviously doesn't work (see comment): https://gist.github.com/kuraga/b0aa3d66fc0620f03b11
you can use async module, specifically async.parallel in order to run two functions in parallel
for example:
async.parallel([
function(callback){
// run your function once
},
function(callback){
// run your function the second time
}
],
// optional callback
function(err, results){
// the results array will equal ['one','two'] even though
// the second function had a shorter timeout.
});
I have the following files:-
target.js
var target = function(repository, logger) {
return {
addTarget : function(target) {
repository.add(target).then(
function (newTarget) {
console.log("added");
logger.info("added");
},
function (err) {
console.log("error");
logger.info("error");
}
);
}
};
};
module.exports = target;
targetTest.js
var chai = require("chai"),
expect = chai.expect,
sinon = require("sinon"),
Promise = require("bluebird"),
baseTarget = require("../target");
describe("target", function(){
it("should log error when it occurs", function() {
var mockRepository = {
add : sinon.stub().returns(Promise.reject(new Error()))
};
var mockLogger = {
info : sinon.spy()
};
var target = baseTarget(mockRepository, mockLogger);
target.addTarget("target");
expect(mockLogger.info.calledWith("error")).to.be.true;
});
});
The issue I have is that expect(mockLogger.info.calledWith("error")).to.be.true; returns false because add method on the repository is async and so hasn't executed yet. Is there a pattern for doing this properly.
This is really more of a question about 'how Promises work' than how they work within test frameworks - the answer to which is that their behaviour remains exactly the same.
Is there a pattern for doing this properly.
It is not so much a pattern as it is what Promises are built to do. Each success handler of a then is executed in sequence on success of the last. In your code we can return the Promise created by calling repository#add as you would if you wanted to use its result or perform some external dependent operation outside of addTarget:
addTarget: function (target) {
return repository
// ^^^^^^
.add(target)
.then(function (newTarget) {
console.log("added");
logger.info("added");
}, function (err) {
console.log("error");
logger.info("error");
});
}
Then place your expectation inside a then that will be executed on success of all members of the Promise chain created in addTarget:
target.addTarget("target").then(function () {
expect(mockLogger.info.calledWith("error")).to.be.true;
cb();
});
Asynchronous Tests
You will notice in the example above that there is also a call to a function cb. Due to your test being asynchronous you need to 'tell' the test framework when the test has completed. This is most often done by declaring your it function with a parameter, from which the framework will infer that the test is asynchronous and pass in a callback:
describe("target", function () {
it("should log error when it occurs", function (cb) {
// ^^^^
});
});
I'm trying to build a scraper using Node.js where I need some help implementing the callback pattern properly.
I'm having trouble implementing it the right what. What I am looking to do is something like this
var client = function(){};
client.prototype.init = function() {
// do something
}
client.prototype.A = function(callback) {
// do something
// run callback
if(recursive_condition_fulfilled)
myclient.A(callback)
}
var myClient = new client();
var myCallback = function(callback){
// do something
}
myClient.init();
myClient.A(myCallback);
The problem arises when I have an async function B() which runs inside A()
client.prototype.A = function(callback) {
// do something
this.B();
// wait for B
// once B is done
// run callback()
// then run the following
if(recursive_condition_fulfilled)
myclient.A(callback)
}
client.prototype.B = function(callback) {
// do something
// run callback
}
How do I implement the later part when B is resolved? (where it says)
// wait for B
// once B is done
// run callback()
I have a handler (callback), an object to handle and four functions, which collect the data to object. In my case I wish to asynchronously call four data retrievers and when execution of all four is complete, handle the resulting object (something similar to the following):
var data = {};
function handle (jsObj) {}
// data retrieving
function getColorData () {}
function getSizeData () {}
function getWeightData () {}
function getExtraData () {}
data.color = getColorData();
data.size = getSizeData();
data.weight = getWeightData();
data.extra = getExtraData();
handle( data );
Of course, this code will not work properly. And if I chain data retrieving functions, they will be called one after another, right?
All four functions should be called asynchronously, cause they are being executed for too long to call them one by one.
Updated:
Thanks to everybody for your suggestions! I prefered $.Deferred(), but I found it slightly difficult to make it work the way I need. What I need is to asynchronously make a view, which requires four kinds of data (extraData, colorData, sizeData & weightData) and I have three objects: App, Utils & Tools.
Just a small description: view is created by calling App.getStuff passed App.handleStuff as a callback. Callback in the body of App.getStuff is called only $.when(App.getExtraData(), App.getColorData(), App.getSizeData(), App.getWeightData()). Before that Utils.asyncRequest passed Tools.parseResponse as a callback is called.
So, now the question is should I create four deferred objects inside each App.get*Data() and also return deferred.promise() from each of them?
And should I deferred.resolve() in the last function in my order (Tools.parseResponse for App.getExtraData in my example)?
var view,
App,
Utils = {},
Tools = {};
// Utils
Utils.asyncRequest = function (path, callback) {
var data,
parseResponse = callback;
// do something with 'data'
parseResponse( data );
};
// Tools
Tools.parseResponse = function (data) {
var output = {};
// do something to make 'output' from 'data'
/* So, should the deferred.resolve() be done here? */
deferred.resolve(output);
/// OR deferred.resolve();
/// OR return output;
};
// App
App = {
// Only one method really works in my example
getExtraData : function () {
var deferred = new jQuery.Deferred();
Utils.asyncRequest("/dir/data.txt", Tools.parseResponse);
return deferred.promise();
},
// Others do nothing
getColorData : function () { /* ... */ },
getSizeData : function () { /* ... */ },
getWeightData : function () { /* ... */ }
};
App.getStuff = function (callback) {
$.when(
App.getExtraData(),
App.getColorData(),
App.getSizeData(),
App.getWeightData()
)
.then(function (extraData, colorData, sizeData, weightData) {
var context,
handleStuff = callback;
// do something to make all kinds of data become a single object
handleStuff( context );
});
};
App.handleStuff = function (stuff) { /* ... */ };
/// RUN
view = App.getStuff( App.handleStuff );
I did not expect the code in my example above to work, it is for illustrative purposes.
I've been trying to solve this for quiet a long time and it still gives no result. The documentation for jQuery.Deferred() and discussions around this, unfortunately, did not help me. So, I would be very glad and greatful for any help or advise.
Conceptually, you would use a counter that gets incremented as each asynchronous call completes. The main caller should proceed after the counter has been incremented by all the asynchronous calls.
I think what you're looking for are Promises / Deferreds.
With promises you can write something like:
when(getColorData(), getSizeData(), getWeightData(), getExtraData()).then(
function (colorData, sizeData, weightData, extraData) {
handle(/*..*/);
}
)
The get*Data() functions will return a promise that they fulfill when their assynchronous call is complete.
Ex:
function getData() {
var promise = new Promise();
doAjax("getData", { "foo": "bar" }, function (result) {
promise.resolve(result);
});
return promise;
}
The when simply counts the number arguments, if all it's promises are resolved, it will call then with the results from the promises.
jQuery has an OK implementation: http://api.jquery.com/jQuery.when/
What I could suggest for this scenario would be something like that.
write a function like this
var completed = 0;
checkHandler = function() {
if(completed == 4) {
handle(data);
}
}
where completed is the number of positive callbacks you must receive.
As soon as every function receives a callback you can increment the "completed" counter and invoke the checkHandler function. and you're done!
in example
function getColorData() {
$.get('ajax/test.html', function(data) {
completed++;
checkHandler();
});
}