I am currently writing an integration test with Mocha, Chai, and WebdriverIO. The WebdriverIO syntax requires a chain of promises to navigate through the browser, an example of which is below:
it('sign in and out test', function() {
return client
.url(Page.url)
.pause(20000)
.waitForVisible(HomePage.signInDropdown, 10000)
.click(HomePage.signInDropdown)
}
This leads to long blocks of code with every step laid out explicitly. Since some of the steps (such as logging in and logging out) are used frequently throughout different tests, I want to modularize those snippets of code through callbacks. However, the following syntax, which works without a nested callback, fails:
function myCallback(){
console.log('This is where I''d add promises');
}
it('sign in and out test',function() {
return client
.url(Page.url)
.pause(20000)
.then(function() {
myCallback();
}
.waitForVisible(HomePage.signInDropdown, 10000)
.click(HomePage.signInDropdown)
}
The following different syntax in the callback also fails:
function myCallback(){
return client
.url(Page.url)
console.log('This is a callback using return');
}
Given that promises are mostly intended to replace callbacks, is it possible in this special case to continue the promise chain through a callback?
myCallback() is not returned from .then().
.then(function() {
// `return` value from `myallback()`
return myCallback();
})
after logout promise resolve we need to do other works in chain.
Please check this,
function myCallback(){
return client
.url(Page.url)
}
it('sign in and out test',function() {
return client
.url(Page.url)
.pause(20000)
.then(function() {
myCallback()
.waitForVisible(HomePage.signInDropdown, 10000)
.click(HomePage.signInDropdown);
}
}
Related
I have the following code:
function MyPromise(configFunction) {
let nextSuccessCallBack = undefined;
let nextResolve = undefined;
configFunction(function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
});
return {
then: function(successCallback) {
nextSuccessCallBack = successCallback;
return new MyPromise(function(resolve) {
nextResolve = resolve;
})
}
}
}
new MyPromise(function(resolve, reject) {
resolve('new message');
}).then(function(message) {
console.log(message);
return 'another message'
}).then(function(message) {
console.log(message)
console.log('here')
})
In this example, it seems that the nextSuccessCallBack is set to be the callback functions within .then, then its value within the setTimeout function is now populated. However, this confuses me. I thought that when we reach the return statement in the constructor, we return the object and effectively stop the function? If that the case then how does the program even get to the setTimeout?
This is not a correct Promise implementation. It clearly has no capabilities for rejections, but also for the implemented fulfilment feature it does not comply with the Promises/A+ specification. Just to give two examples:
It does not comply with rule 2.1.2.2
When fulfilled, a promise must have a value, which must not change.
....nor with rule 2.2.2.3:
If onFulfilled is a function it must not be called more than once.
In your implementation, if you would add a second call to resolve:
new MyPromise(function(resolve, reject) {
resolve('new message'); resolve('new message2');
}).then((function(message) {
console.log(message);
// ... etc
})
...then both calls to resolve would fire the then callback, and show that the promised value was modified after the first time it was set. This is in complete violation of the principle of promises: promises can only resolve once.
It does not comply with rule 2.2.6:
then may be called multiple times on the same promise.
If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
This does not happen if we use the following code:
let p = new MyPromise(resolve => resolve("value"));
p.then(console.log); // This callback is called
p.then(console.log); // This callback is not called -> violation!
These are basic shortcomings, and this is just the tip of the iceberg.
If you are interested in how it could be implemented in compliance with Promise/A+, then have a look at one I did a few years ago with a step-by-step explanation.
As to your question
how does the program even get to the setTimeout?
When your main code executes this:
new MyPromise(function(resolve, reject) {
resolve('new message');
})
...then the parameter variable configFunction is initialised with that callback function. The MyPromise constructor calls it, passing it the following callback as first argument:
function(message){
setTimeout(function(){
if(nextSuccessCallBack) {
var result = nextSuccessCallBack(message);
if(result && result.then) {
result.then(nextResolve);
} else {
nextResolve && nextResolve(result);
}
}
})
}
So that means that resolve in your main code's callback function is initialised with the above callback function. Then your main code's callback function calls resolve with a string argument. Since resolve is the above callback function, we can see it gets executed with message initialised to "new message". This function executes setTimeout.
The code in the snippet does solve the purpose but, it is confusing as is a bad implementation of a Promise according to the way MDN Uses Promises in JavaScript for better code efficiency and understanding.
The above code can also be written this way:
const examplePromise = new Promise((resolve, reject) => {
resolve("Another Message");
});
console.log("New Message");
examplePromise.then((message) => {
console.log(message);
});
Now, for better understading of the concept of Promises in JavaScript, I'll take another example:
Let's say I want to create a program which says hello and then after 2 seconds says How Are You?
There are two ways of solving this
Just using the setTimeout() function which executes a function after certain period of time
Using promises with setTimeout()
Case I (Using setTimeout()):
console.log("hello"); //Saying hello for the first time
setTimeout(function () {
console.log("How Are You?");
}, 2000); //2000 milliseconds is 2 seconds
Case II (Using Promises)
console.log("hello");
const example = new Promise((resolve) => {
setTimeout(() => {
resolve("How Are You?");
}, 2000);
});
example.then((message) => {
console.log(message);
});
Now, for simple cases like logging a message after 2 seconds do not require Promises. You may use them (No problem) but actually, Promises are used in cases where, you wait for a function to execute a Database Query or you need to wait for a server to give you some HTML Response or while using WebAPIs, etc.
P.S: setTimeout() is just an example. It is not a rule that you always have to use setTimeout() while writing a Promise. If you are fetching data using a WebAPI, you usually write $.ajax(...).then(...) or fetch(...).then(...) instead of setTimeout()
I've read some tutorials online for the Promises method but I'm still a bit confused.
I have a Node app.js which performs several functions including connecting to a db.
db.connect(function(err) {
setupServer();
if(err) {
logger.raiseAlarmFatal(logger.alarmId.INIT,null,'An error occurred while connecting to db.', err);
return;
}
Now I have written a mocha unit test suite, which encapsulates this app and performs several request calls to it. In some cases what occurs is that the the test initializes without confirmation that the db has successfully connected i.e: setupServer() has been performed.
How would I implement the promises method to this bit of asynchronous code, and if not promises, what should I use ? I have already tried event emitter but this still does not satisfy all the requirements and causes failures during cleanup.
If you're using mocha, you should use asynchronous code approach. This way you can instruct mocha to wait for you to call done function before it goes on with the rest.
This would get you started:
describe('my test', function() {
before(function(done) {
db.connect(function(err) {
setupServer(done);
});
})
it('should do some testing', function() {
// This test is run AFTER 'before' function has finished
// i.e. after setupServer has called done function
});
});
assuming that your setupServer calls the done function when it's done:
function setupServer(done) {
// do what I need to do
done();
}
You will need to use Promise inside the body of function that has async work. For your case, I think that is setupServer() which you said contains ajax requests.
conts setupServer = () => {
return new Promise((resolve, reject) => {
//async work
//get requests and post requests
if (true)
resolve(result); //call this when you are sure all work including async has been successfully completed.
else
reject(error); //call this when there has been an error
});
}
setupServer().then(result => {
//...
//this will run when promise is resolved
}, error => {
//...
//this will run when promise is rejected
});
For further reading:
Promise - MDN
I have a native javascript promise chain that looks a little like this:
function chain() {
promiseFunction1().then(function(data) {
console.log("some message");
return promiseFunction2();
}).then(function(data) {
console.log("some message");
return promiseFunction3();
}).then(function(data) {
console.log("some message");
return promiseFunction4();
}).catch(function(error) {
console.error(error.stack);
});
}
the promise functions would look a little like this:
function promiseFunction() {
return new Promise(function(resolve,reject) {
someCallbackfunction(arg, function(err, data){
if (err) {
return reject(err);
}
console.log("some message");
return resolve(data);
});
});
}
My code seems to resolve fine from what I can tell (no errors and I can tell from terminal feedback that the operations I needed started running) but no matter what I seem to try I cannot for the life of me seem to get any form of console logging.
1) Why are these statements not printing like I expect them to?
2) How can I go about getting back my verbose output?
It turned out that in the end the problem was external.
Somewhere in my promise chain I called an external library with a callback function but the library never responded causing my chain to wait forever.
If you experience something similar I encourage you to double check all of the functions in the chain for a similar occurrence.
A quick way to debug this could be to place a timeout in each promise function in the chain that resolves it after x amount of time, that way you can at least get your logging results without having to stumble in the dark forever.
I am trying to understand deferred and promise. I dont want to use any library angularfire etc., before understanding the core concept. This is what i am trying to do and always getting a wrong status. Please advise.
........
var defObj = $.Deferred();
var fbref = new Firebase(<<firebase url>>);
defObj.done(function() {
console.log('Success')
}
);
defObj.fail(function() {
console.log('Fail')
}
);
defObj.resolve(
fbref.authAnonymously(function(error, authData) {
if (error) {
defObj.reject();
}
/*
else if (authData) {
defObj.resolve();
}
*/
});
return defObj.promise();
........
Pls ignore any syntax errors. Earlier I wrapped the fbref.authAnonymously call in a seperate function. In debug mode it was falling to fail but in run mode it was always going to success.
I am sure my firebase instance is not enabled for anonymous authentication.
edited : misspelt title.
Promises are now an official part of JavaScript and you can use them in the latest browsers without a library.
function authAnonymously() {
// 1
var promise = new Promise(
function(resolve, reject) {
var ref = new Firebase(<<firebase url>>);
ref.authAnonymously(function(error, authData) {
if (error) {
reject(error); // 2
} else {
resolve(authData); // 3
}
});
});
}
authAnonymously()
.then((authData) => console.log(authData)) // 4
.catch((error) => console.error(error)); // 5
Here are the five steps in this example
Create a Promise constructor
If the asynchronous action is to error, mark it with the reject() function.
If the asynchronous action is to succeed, mark it with the resolve() function.
Call the authAnonymously() function and begin the promise chain with the then() function. When successful this function will fire off.
Continue the promise chain with the error() function. If the error occurs, the catch() function won't fire, but this error() function will.
Promises work well for one time callbacks. For Firebase, this is great for authentication methods and once() calls. This is not great though for repeated callbacks, like the on() function.
I'm using Mocha to test an asynchronous function that returns a promise.
What's the best way to test that the promise resolves to the correct value?
Mocha has built-in Promise support as of version 1.18.0 (March 2014). You can return a promise from a test case, and Mocha will wait for it:
it('does something asynchronous', function() { // note: no `done` argument
return getSomePromise().then(function(value) {
expect(value).to.equal('foo');
});
});
Don't forget the return keyword on the second line. If you accidentally omit it, Mocha will assume your test is synchronous, and it won't wait for the .then function, so your test will always pass even when the assertion fails.
If this gets too repetitive, you may want to use the chai-as-promised library, which gives you an eventually property to test promises more easily:
it('does something asynchronous', function() {
return expect(getSomePromise()).to.eventually.equal('foo');
});
it('fails asynchronously', function() {
return expect(getAnotherPromise()).to.be.rejectedWith(Error, /some message/);
});
Again, don't forget the return keyword!
Then 'returns' a promise which can be used to handle the error. Most libraries support a method called done which will make sure any un-handled errors are thrown.
it('does something asynchronous', function (done) {
getSomePromise()
.then(function (value) {
value.should.equal('foo')
})
.done(() => done(), done);
});
You can also use something like mocha-as-promised (there are similar libraries for other test frameworks). If you're running server side:
npm install mocha-as-promised
Then at the start of your script:
require("mocha-as-promised")();
If you're running client side:
<script src="mocha-as-promised.js"></script>
Then inside your tests you can just return the promise:
it('does something asynchronous', function () {
return getSomePromise()
.then(function (value) {
value.should.equal('foo')
});
});
Or in coffee-script (as per your original example)
it 'does something asynchronous', () ->
getSomePromise().then (value) =>
value.should.equal 'foo'