Is there a way in Robot Framework to run a javascript method that returns a promise and resolve that promise so I could get a result from it? I tried to achieve it in two ways. The first way was to run the Execute Javascript keyword and pass the function, then set wait for some time (with Sleep) and trying to resolve the promise (it already finished to execute in the browser).
The code I used looks like that:
${promise}= Execute Javascript return runAllTests();
Sleep 30sec
${result}= Set Variable return ${promise}.then(function(result) { return result; });
The result I got with this was just the promise object (I think)
{u'all': {}, u'_setSettlePromisesQueued': {}, u'_setBoundTo': {}, u'_settlePromiseAtPostResolution': {}, u'_isRejectionUnhandled': {}...
I do not paste it all because it's 3000+ characters long, but it's not what I expected for sure. Actually, the result is exactly the same no matter if I put there Sleep keyword or not.
The second way was to use Execute Async Javascript keyword (with modified timeout) and then trying to resolve it.
Set Selenium Timeout 30sec
${result}= Execute Async Javascript return runAllTests().then(function(result) { return result});
The function finished to execute in the browser window, but Robot seems not to care and after 30 seconds it reports TimeoutException with this message:
TimeoutException: Message: asynchronous script timeout: result was not received in 30 seconds
I tried to find another way, maybe some built-in mechanism to handle the promises, but I did not find anything like that. Is there any way to do that? I use Robot with Selenium2Library.
The solution for this is basically in the Selenium2Library documentation. All it takes to make it work is to use the callback function, for example:
Set Selenium Timeout 60sec
${result}= Execute Async Javascript
... var callback = arguments[arguments.length-1];
... runAllTests().then(function() { callback(1); }).catch(function() { callback(0); });
This will set the result to 1 or 0 (as a string, not integer), depending on what is returned by this function (resolved or rejected promise). I was confused by this callback used in this example but it's working.
Following keyword allows getting back the promise response or error message.
PS Execute Async Promise
[Arguments] ${promise} ${timeout}=${PS_MAX_WAIT} ${return_function}=${None} ${failure_marker}=UNEXPECTED_STATE
[Documentation] Wrapper calling a asynchronous JavaScript ${promise} and wait till max ${timeout}, if it's promise returns \ a success or failure.
...
... Failure case:
... - \ the error.message is catched and reported
...
... Success case:
... - When ${return_function} is None, the promise response will be returned directly (default)
... - Otherwise, an additional *then* chain step is added to modify / prepare promise response .
...
... Sample: If ${return_function} is _JSON.stringify(response)_ , a chain step _then( function(response) { return JSON.stringify(response); } )_ is added
[Tags] internal
Set Selenium Timeout ${timeout}
${promise_chain}= Set Variable If '${return_function}'!='${None}' ${promise}.then( function(response) { return ${return_function}; } ) ${promise}
${error_return}= Set Variable '${failure_marker} - ' + error.name + ' - ' + error.message
${result}= Execute Async Javascript var callback = arguments[arguments.length-1]; ${promise_chain}.then(function(response) { callback( response ); }).catch(function(error) { callback( ${error_return} ); });
Should Not Contain ${result} ${failure_marker} js call aborts with ${result} - ${promise_chain}
[Teardown] PS Set Delay and Timeout to Default
[Return] ${result}
Sample robot suite using this keyword see robot-framework_sample_promises.robot.
It interacts with sample page Promises tests, provided by JavaScript Promises: an Introduction
Related
So, I am currently learning about callbacks and promises and I keep getting tripped up when watching tutorials. So i thought that I would put it in an example form and see if anyone could tell me if my thinking is correct. I am currently working with MongoDB and Mongoose.
Here is an example piece of code taken from a tutorial. I believe that this is considered a callback?
user.save((err) => {
if (err) {
return res.status(400).json({
error: "You are not authorized to perform this action.",
})
});
And then this would be considered a promise?
user.save().catch(err => {
return res.status(400).json({
error: "You are not authorized."
})
})
Are there any performance advantages of using a promise over a callback or vice versa?
Thank You!
Callbacks and promises are different but share some concepts.
A callback is simply a function passed to another function as a parameter where that function can be executed at any time.
for example:
function iNeedACallback(callback)
{
// execute a bunch of code...
// use the callback function provided
callBack("a function called 'iNeedACallback'")
}
const callback = (fromFunction) => console.log("I am a callback function called from: " + fromFunction);
// Execute iNeedACallback by passing in the callback
iNeedACallback(callback);
The above code is a very simplistic instance of a callback function - now this can either be executed sequentially(like in the example above) or it can be an async operation on the event loop. (for more info about the event loop: Why do you need to await AJAX calls in JS but not in C#?)
A Promise makes use of callback functions in order to handle async code in a conventional way. The nature of a Promise infers that its some code that will be placed on the event loop as it executed asynchronously and not block any other code while waiting for an operation like a network call.
for example:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const text = "i was only called after 2 seconds :(";
resolve(text);
}, 2000)
})
promise.then((text) => console.log(text))
console.log("i got called immediately :)")
//Output:
//i got called immediately :)
//i was only called after 2 seconds :(
In the above example we give a promise a callback function to execute when an async operation has completed (like a setTimeout) where the most common use cases are network calls like HTTP requests or TCP connections to a database like mongodb.
Back to your original question - your assumption is correct in the sense that your demonstration of a callback and promise is correct, and your question about performance..
Javascript is single threaded so if your callback function is placed on the event loop (which it may or may not be) then it will not block the main execution call stack. Promises are inherently async operation so they will always be placed on the event loop so the performance factor is dependent on the underlying implementation of the callback function - Promises will be async where as some regular callbacks could be sequential and synchronous.
I am attempting to make a simple text game that operates in a socket.io chat room on a node server. The program works as follows:
Currently I have three main modules
Rogue : basic home of rogue game functions
rogueParser : module responsible for extracting workable commands from command strings
Verb_library: module containing a list of commands that can be invoked from the client terminal.
The Client types a command like 'say hello world'. This triggers the following socket.io listener
socket.on('rg_command', function(command){
// execute the verb
let verb = rogueParser(command);
rogue.executeVerb(verb, command, function(result){
console.log(result);
});
});
Which then in turn invokes the executeVerb function from rogue..
executeVerb: function(verb, data, callback){
verb_library[verb](data, callback);
},
Each verb in verb_library should be responsible for manipulating the database -if required- and then returning an echo string sent to the appropriate targets representing the completion of the action.
EDIT: I chose 'say' when I posted this but it was pointed out afterward that it was a poor example. 'say' is not currently async but eventually will be as will be the vast majority of 'verbs' as they will need to make calls to the database.
...
say: function(data, callback){
var response = {};
console.log('USR:'+data.user);
var message = data.message.replace('say','');
message = ('you say '+'"'+message.trim()+'"');
response.target = data.user;
response.type = 'echo';
response.message = message;
callback(response);
},
...
My problem is that
1 ) I am having issues passing callbacks through so many modules. Should I be able to pass a callback through multiple layers of modules? Im worried that I'm blind so some scope magic that is making me lose track of what should happen when I pass a callback function into a module which then passes the same callback to another module which then calls the callback. Currently it seems I either end up without access to the callback on the end, or the first function tries to execute without waiting on the final callback returning a null value.
2 ) Im not sure if Im making this harder than it needs to be by not using promises or if this is totally achievable with callbacks, in which case I want to learn how to do it that way before I summon extra code.
Sorry if this is a vague question, I'm in a position of design pattern doubt and looking for advice on this general setup as well as specific information regarding how these callbacks should be passed around. Thanks!
1) Passing callback trough multiple layers doesn't sound like a good idea. Usually I'm thinking what will happen, If I will continiue doing this for a year? Will it be flexible enough so that when I need to change to architecture (let's say customer have new idea), my code will allow me to without rewriting whole app? What you're experiencing is called callback hell. http://callbackhell.com/
What we are trying to do, is to keep our code as shallow as possible.
2) Promise is just syntax sugar for callback. But it's much easier to think in Promise then in callback. So personally, I would advice you to take your time and grasp as much as you can of programming language features during your project. Latest way we're doing asynchronus code is by using async/await syntax which allows us to totally get rid of callback and Promise calls. But during your path, you will have to work with both for sure.
You can try to finish your code this way and when you're done, find what was the biggest pain and how could you write it again to avoid it in future. I promise you that it will be much more educative then getting explicit answear here :)
Asynchronousness and JavaScript go back a long way. How we deal with it has evolved over time and there are numerous applied patterns that attempt to make async easier. I would say that there are 3 concrete and popular patterns. However, each one is very related to the other:
Callbacks
Promises
async/await
Callbacks are probably the most backwards compatible and just involve providing a function to some asynchronous task in order to have your provided function be called whenever the task is complete.
For example:
/**
* Some dummy asynchronous task that waits 2 seconds to complete
*/
function asynchronousTask(cb) {
setTimeout(() => {
console.log("Async task is done");
cb();
}, 2000);
}
asynchronousTask(() => {
console.log("My function to be called after async task");
});
Promises are a primitive that encapsulates the callback pattern so that instead of providing a function to the task function, you call the then method on the Promise that the task returns:
/**
* Some dummy asynchronous task that waits 2 seconds to complete
* BUT the difference is that it returns a Promise
*/
function asynchronousTask() {
return new Promise(resolve => {
setTimeout(() => {
console.log("Async task is done");
resolve();
}, 2000);
});
}
asynchronousTask()
.then(() => {
console.log("My function to be called after async task");
});
The last pattern is the async/await pattern which also deals in Promises which are an encapsulation of callbacks. They are unique because they provide lexical support for using Promises so that you don't have to use .then() directly and also don't have to explicitly return a Promise from your task:
/*
* We still need some Promise oriented bootstrap
* function to demonstrate the async/await
* this will just wait a duration and resolve
*/
function $timeout(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
/**
* Task runner that waits 2 seconds and then prints a message
*/
(async function() {
await $timeout(2000);
console.log("My function to be called after async task");
}());
Now that our vocabulary is cleared up, we need to consider one other thing: These patterns are all API dependent. The library that you are using uses callbacks. It is alright to mix these patterns, but I would say that the code that you write should be consistent. Pick one of the patterns and wrap or interface with the library that you need to.
If the library deals in callbacks, see if there is a wrapping library or a mechanism to have it deal in Promises instead. async/await consumes Promises, but not callbacks.
Callbacks are fine, but I would only use them if a function is dependent on some asynchronous result. If however the result is immediately available, then the function should be designed to return that value.
In the example you have given, say does not have to wait for any asynchronous API call to come back with a result, so I would change its signature to the following:
say: function(data){ // <--- no callback argument
var response = {};
console.log('USR:'+data.user);
var message = data.message.replace('say','');
message = ('you say '+'"'+message.trim()+'"');
response.target = data.user;
response.type = 'echo';
response.message = message;
return response; // <--- return it
}
Then going backwards, you would also change the signature of the functions that use say:
executeVerb: function(verb, data){ // <--- no callback argument
return verb_library[verb](data); // <--- no callback argument, and return the returned value
}
And further up the call stack:
socket.on('rg_command', function(command){
// execute the verb
let verb = rogueParser(command);
let result = rogue.executeVerb(verb, command); // <--- no callback, just get the returned value
console.log(result);
});
Of course, this can only work if all verb methods can return the expected result synchronously.
Promises
If say would depend on some asynchronous API, then you could use promises. Let's assume this API provides a callback system, then your say function could return a promise like this:
say: async function(data){ // <--- still no callback argument, but async!
var response = {};
console.log('USR:'+data.user);
var message = data.message.replace('say','');
response.target = data.user;
response.type = 'echo';
// Convert the API callback system to a promise, and use AWAIT
await respone.message = new Promise(resolve => someAsyncAPIWithCallBackAsLastArg(message, resolve));
return response; // <--- return it
}
Again going backwards, you would also change the signature of the functions that use say:
executeVerb: function(verb, data){ // <--- still no callback argument
return verb_library[verb](data); // <--- no callback argument, and return the returned promise(!)
}
And finally:
socket.on('rg_command', async function(command){ // Add async
// execute the verb
let verb = rogueParser(command);
let result = await rogue.executeVerb(verb, command); // <--- await the fulfillment of the returned promise
console.log(result);
});
-- EDIT --
I encountered a weird thing recently about promises, but I guess it's maybe because it's against the philosophy of promises.
Considering the following code :
// Assuming Auth is just a simple lib doing http requests with promises
Auth.signup()
.then(succCall, errCall)
.then(loginSucc, loginErr)
// My callbacks here
function succCall (){
// OK, send second promise
console.log('succCall');
return Auth.login();
}
function errCall(){
// I do some things here and now
// I want to break out from here
console.log('errCall');
}
function loginSucc(){
// This is the callback of the login method when it went OK
// I want to enter here ONLY if with go through the succCall
console.log('loginSucc');
}
function loginErr(){
// This is the callback of the login method when it went not ok
// I want to enter here ONLY if with go through the succCall
console.log('loginErr');
}
Here if something goes wrong in Auth.signup(), this is what show :
errCall, loginSucc
if i do a $q.reject() in the errCall this is what happens :
errCall, loginErr
and this is what i want :
errCall... finish, stop here
Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc...
I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered.
-- EDIT --
I think i was misunderstood by some mean, i want to totally break the chain without check in any other "then" if something went wrong.
As if i was saying : if first then is wrong stop here, if first then ok continue, if second "then" ok continue, if third "then" wrong, stop
// Just like if i did the following but by chainning "then" methods
// My callbacks here
function succCall (){
// OK, send second promise
return Auth.login().then(loginSucc, loginErr);
}
My point is, i don't want only one error handler if i have many "then" chained
What is effectively happening is this:
try {
try {
var a = succCall();
} catch(e1) {
a = errCall(e1);
}
var b = loginSucc(a);
} catch(e2) {
b = loginErr(e2);
}
You can break out of the chain by calling
return $q.reject('Reason Err was called');
in your errCall() function.
EDIT:
As OP remarked by calling $q.reject the code will enter the loginErr function.
Alternatively you can modify your code like this:
Auth.signup()
.then(function(a) {
succCall()
return loginSucc(a).then(null, loginErr);
}, errCall)
You can read more in these two SO question:
Break promise chain
Break Out of then promises in
Angularjs
This also is a helpful read : Flattening Promise Chains
errCall function needs tor return a promise, and that promise needs to be rejected for loginErr to be fired.
function errCall(){
// i do some things here and now
return $q(function(resolve, reject) {
// auto reject
reject();
});
}
Alternatively try .catch:
Auth.signup()
.then(succCall)
.then(loginSucc)
.catch(function(err){
// caught error, problem is you won't know which function errored out, so you'll need to look at the error response
});
Just don't pass any errCall or loginErr to then and use catch() in the end of the promise chain and it will be interrupted on first error, which will be passed to catch(). If you want explicitly process error of Auth.signup() then your errCall should look like this:
function (err) {
if(isFatal(err)) {
return Promise.reject(new Error('Fatal!')); //`catch()` handler will be called with `new Error('Fatal!')`
} else {
return 'something'; //next `then()` handler will be called with 'something'
}
}
Your best option is to return a promise that is never resolved from errCall():
function errCall() {
console.log('errCall');
return $q.defer().promise;
}
But you are right, what you are trying to do is "against the philosophy of promises".
Why you shouldn't do it
It is of course a problem that your loginSucc function is called when an error occurs during evaluation of the first promise. However, that can be fixed by rejecting once again in errCall as others have already pointed out. But you should not try to avoid the execution of loginErr, otherwise something is conceptually wrong with your code.
The evaluation of the expression
Auth.signup().then(succCall, errCall)
yields another promise. The contract is that a promise has a then() method taking two callbacks as parameters, one for success and one for failure. The contract is also that the success callback is called when the promise is evaluated successfully and that the error/failure callback is called in all other cases. If you intend to never call either of those, don't use a promise!
Suppose I have the following Parse cloud code:
// assume myObj is a parse object
myObj.set("field1", "foo");
Parse.Promise.as().then(function()
myObj.save(myObj, {
success: function(savedObj) {
// A
return Parse.Promise.as();
},
error: function(myObj, error) {
// B
return Parse.Promise.as();
}
});
// C
// note that we can get here without any return statement being called
}).then(function() {
// D
});
(Now, i know it would be simpler to just use promises for the whole thing:
myObj.save().then(
...
...but there are some functions that don't return promises, so sometimes you have no choice but to mix Backbone-style success/error blocks with promises.)
My question:
What happens when C is reached? Does execution pause on this promise until one of those return statements is reached, and then execution reaches D? Does execution advance directly to D after reaching C, without waiting for a return statement? Is this an error?
In other words, is it possible for execution to happen in the order C, D, A/B? Or will it always be C, A/B, D? (Or, I suppose, if save finishes crazy fast, something like A/B, C, D?)
Your returns are from the inner functions. If it was up to me I'd promisify the save function itself. However, if you're convinced you don't want to do this you still have to return a Parse.Promise from the then if you want it to wait for anything.
The then function returns a new promise and resolves that promise (executes further thens) when its return value is resolved. If that's just a value it will not wait for anything - if it's a promise it will wait for it in turn to resolve.
Please look at how to promisify for further reading.
In your example - this would look something like:
myObj.set("field1", "foo");
Parse.Promise.as().then(function(){
var p = Parse.Promise();
myObj.save(myObj, {
success: p.resolve.bind(p), // on success, resolve the promise
error: p.reject.bind(p) // on failure, reject it
});
// any code here _will_ execute before the `then` is called.
return p; // return the promise so `then` will wait
}).then(function(savedObj) {
// this will always run after `myObj.save` completed
// you can add a catch handler for the error case
});
However, if we pay attention we can notice Parse's save method already returns a promise - Parse promisified it for us - so this code can be significantly reduced to:
myObj.set("field1", "foo");
Parse.Promise.as().then(function(){
return myObj.save(myObj)
}).then(function(savedObj) {
// this will always run after `myObj.save` completed
// you can add a catch handler for the error case
});
Which in turn can be reduced to:
myObj.set("field1", "foo");
myObj.save().then(function(savedObj){
// object save is done here
});
Answer seems to be that it won't wait for A or B -- it'll move on, probably with D executing before A or B.
In any case, it's basically a bug -- though not one the runtime will complain about -- to invoke asynchronous code (like I do with save()) but not explicitly return a local promise at the end of a then function block that would make the bigger promise wait until the asynchronous code finishes. In other words, I should do something like Benjamin Gruenbaum's answer suggests.
As a rule of thumb just keep returning promises, they will be automagically resolved. All Parse async methods return promises so just keep returning until you are done.
I wouldn't recommend to use the success and error methods. Using callbacks and promises together is not a good idea since you have to write a lot of extra code to account for it. If everything in your app return promises you can remove a block or add a another one very easily. Just create functions that return a promise.
Also, how you return promises while vary depending on the scope needed in each block.
So for example:
function myPromise (a) {
return Parse.Promise.as({name: 'David Bowie', a : a});
}
myObj.set("a", 1);
myObj.save(obj).then(function(obj) {
var a = obj.get('a');
return Parse.Promise.as()
.then(function() {
return Parse.Object.saveAll([])
.then(function() {
a += 1
return Parse.Promise.as(a);
})
})
}).then(function(a){
return myPromise(a);
})
.then(function(davidBowie) {
console.log(davidBowie.name);
console.log(davidBowie.a);
})
.fail(function() {
// handle error
})
I am looking for a way to run some code in nodejs after N amount of seconds.
Tried setTimeout() but it seems to completely block on it until the time is out but this is not what I want since my server is still sending and receiving events.
Any advice?
Actually, setTimeout is asynchronous, so it will not block.
setTimeout(function(){
// this code will only run when time has ellapsed
}, n * 1000);
// this code will not block, and will only run at the time
Actually setTimeout() does exactly what you are asking for, it does not block and will execute the given function at some time in the future.
However, it can be tricky to understand what's going on in Node.js. I highly recommend making the investment in learning how to use the Promise API. It can be confusing at first, but gives you a very flexible structure for controlling ansynchronous events. Here is an example I wrote as part of learning how to use the Promise API. You will see that it actually uses setTimeout(), but embeds it in a Promise. Hopefully this code is self explanatory and helps you achieve what you need.
/*
* Try out javascript Promise code in Node.js
*
*/
"use strict";
function getRandomBoolean() {
return Math.random() > 0.5;
}
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
for (let i = 0; i < 5; i++) {
// Create a promise, which will randomly succeed (and call resolve) or
// fail (and call reject) after a random time interval
let intervalMS = getRandomInt(5000);
let promise = new Promise(function (resolve, reject) {
setTimeout(() => {
if (getRandomBoolean()) {
// Success - Call resolver function
resolve(i+" Hooray!");
} else {
// Treat this as an error - Call reject function
reject(i+" Sorry!");
}
}, intervalMS);
});
// When the promise is complete, show the results
promise.then(
// The first function is the resolve function, to be called
// with a result param upon successful completion of async task
result => console.log("Success: "+result),
// Next is reject function, to be called with an error parameter when something failed
error => console.log("Failure: "+error)
);
// Flow of execution falls through to here without blocking
console.log ("Created promise "+i+", will complete in "+intervalMS+" ms");
}
If you run the above example in Node.js (or actually it should run in the browser too, I just haven't tested it there) you will see output something like the following:
Created promise 0, will complete in 853 ms
Created promise 1, will complete in 2388 ms
Created promise 2, will complete in 2738 ms
Created promise 3, will complete in 3053 ms
Created promise 4, will complete in 652 ms
Success: 4 Hooray!
Failure: 0 Sorry!
Failure: 1 Sorry!
Success: 2 Hooray!
Success: 3 Hooray!
Note that the "Created promise..." output comes out first, showing you that the execution falls through without blocking.