Protractor, when should I use then() after a click() - javascript

I'm running an Angular app and when testing on protractor a click(), I don't know when should I resolve the promise with a then().
I found this on Protractor API:
A promise that will be resolved when the click command has completed.
So, should I use click().then() in every click?

So, should I use click().then() in every click?
Definitely not.
It's not needed because Protractor/WebDriverJS has this mechanism called "Control Flow" which is basically a queue of promises that need to be resolved:
WebDriverJS maintains a queue of pending promises, called the control
flow, to keep execution organized.
and Protractor waits for Angular naturally and out-of-the-box:
You no longer need to add waits and sleeps to your test. Protractor
can automatically execute the next step in your test the moment the
webpage finishes pending tasks, so you don’t have to worry about
waiting for your test and webpage to sync.
Which leads to a quite straight-forward testing code:
var elementToBePresent = element(by.css(".anotherelementclass")).isPresent();
expect(elementToBePresent.isPresent()).toBe(false);
element(by.css("#mybutton")).click();
expect(elementToBePresent.isPresent()).toBe(true);
Sometimes though, if you experience synchronization/timing issues, or your app under test is non-Angular, you may solve it by resolving the click() explicitly with then() and continue inside the click callback:
expect(elementToBePresent.isPresent()).toBe(false);
element(by.css("#mybutton")).click().then(function () {
expect(elementToBePresent.isPresent()).toBe(true);
});
There are also Explicit Waits to the rescue in these cases, but it's not relevant here.

Yes, you should.
Maybe right now it's not necessary, but maybe in next versions it is.
So, if click return a promise, you should use it.
http://www.protractortest.org/#/api?view=webdriver.WebElement.prototype.click

Related

Javascript promise that calls "then" immediately

I'm using JavaScript promises extensively in a single-page app I am developing. In certain contexts, I need the "then" method to run synchronously if the promise has already been resolved. For this purpose, I have written a custom promise implementation as a wrapper class, which works fine, but prevents me from using async/await. So I would like to know if there is a way to have both, since it seems to me that async/await is really just syntactic sugar around "then."
The custom promise implementation already implements the PromiseLike TypeScript interface, but apparently async/await always need a native promise. Why?
One possibility I have thought of is to replace the "then" method of a real promise object, instead of building my own wrapper on top. Will this work?
The reason it's important for "then" to be called immediately is that the end of the promise chain is a property of a React component, and the React component displays a loading indicator until the promise is resolved. Without my wrapper, the loading indicator is displayed briefly every time the component updates, which also breaks some user interaction.
Maybe there is a different way to solve this problem. This is my first dive into the world of JavaScript.
I'm using TypeScript and targeting ES6.
but apparently async/await always need a native promise.
No it does not. await works on an object that has a .then method.
Without my wrapper, the loading indicator is displayed briefly every time the component updates, which also breaks some user interaction.
That's not caused by awaiting resolved promises. The .then is executed in a microtask, which means that if the promise really resolved already, the .then will execute directly after the engine executed it's current task, so it gets executed before the browser rerenders.
let promise = Promise.resolve(1);
setTimeout(() => { // Make sure the promise resolved
console.log("sync");
promise.then(() => console.log("then"));
requestAnimationFrame(() => console.log("redraw"));
console.log("sync end");
}, 1000);
You'll see sync, sync end, then, redraw in the console.

Reject and terminate promise on external event

I want to be able to reject and stop the rest of the promise from running if an external event occurs. This is the example usecase:
new Promise((resolve,reject)=>{
websocket.onerror=reject;
//do processing here
websocket.onerror=undefined;
resolve(...);
});
This has the intended effect of rejecting the promise if an error occurs while the promise is running. However, the problem is that the rest of the promise will continue running even if a rejection occurs.
Using async/await the above is not possible at all.
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
However, the problem is that the rest of the promise will continue running even if a rejection occurs.
This is a basic misunderstanding (and you're not alone in it!). There is no "rest of the promise." A promise is just a means of observing the completion of an asynchronous process. It's the process, not the promise, that's continuing.
How you cancel that process (and whether you can) depends entirely on what that process is and whether it provides a means of cancelling it, which is unrelated to promises themselves. You seem to be using a web socket, so you'd need to use the web socket API to cancel whatever you have it doing (or to send a message to the other end to tell it to stop what it's doing).
For instance: Suppose the promise were waiting for a timer (setTimeout) to fire, and would resolve when it did. Then some other thing happens and you no longer want that. Rejecting the promise just rejects the promise, it doesn't have any effect on the timer. You'd need to cancel the timer, too (clearTimeout).
Re your edit:
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
No, the code in the promise executor (the function you pass new Promise) is run synchronously. Again, there's no "rest of the code" to cancel. There may well be asynchronous callbacks in there, or a process the code starts you need to send a cancellation too, but that's not going to require putting every line in its own promise, not at all.
Understanding the answer to this question may help you:
When you create the promise, it is executed synchronously. So this line is executed:
websocket.onerror=reject;
At this point, your code begins to process. If there is an event of websocket error, it is put in the js event loop, but your promise is still executing synchronously. Then you unhook the websocket's error handler, and resolve. The promise will resolve even if there was an error. At this point the call for resolve is also added to js' event loop. Then the next js tick executes, and maybe reject is called, maybe not, but it doesn't matter at this point because you resolved synchronously, and promises never change their minds once they've resolved or rejected.
So the key takeaway here is that creating a promise executes it synchronously. It's not a thread that you can cancel while waiting for other events. The promise' resolution or rejection is executed asynchronously, but that doesn't help you at all.
To cancel a promise, you'll need some pretty basic stuff such as
if(someOtherVariableThatDeterminesCancelation){
reject()
}

What is the difference between browser.sleep() and browser.wait() methods?

Facing timing issue with protractor. sometimes my protractor test cases fails due to network or performance issues. I have solved existing issues with browser.sleep(). Later I came to know about browser.wait().
What is the difference between them and which one is better for solving network or performance issues.
When it comes to dealing with timing issue, it is tempting and easy to put a "quick" browser.sleep() and move on.
The problem is, it would some day fail. There is no golden/generic rule on what sleep timeout to set and, hence, at some point due to network or performance or other issues, it might take more time for a page to load or element to become visible etc. Plus, most of the time, you would end up waiting more than you actually should.
browser.wait() on the other hand works differently. You provide an Expected Condition function for Protractor/WebDriverJS to execute and wait for the result of the function to evaluate to true. Protractor would continuously execute the function and stop once the result of the function evaluates to true or a configurable timeout has been reached.
There are multiple built-in Expected Conditions, but you can also create and use a custom one (sample here).
sleep: Schedules a command to make the driver sleep for the given amount of time
wait: Schedules a command to wait for a condition to hold or promise to be resolved.
Reference for detail: http://www.protractortest.org/#/api?view=webdriver.WebDriver.prototype.sleep
browser.sleep()
Schedules a command to make the driver sleep for the given amount of time.
browser.wait()
Schedules a command to wait for a condition to hold or promise to be resolved.
This function blocks WebDriver's control flow, not the javascript runtime. It will only delay future webdriver commands from being executed (e.g. it will cause Protractor to wait before sending future commands to the selenium server), and only when the webdriver control flow is enabled.
Documentation link http://www.protractortest.org/#/api

Javascript, Node, Promises, and recursion

I'm having trouble controlling execution flow. This is a follow-on to node.js, bluebird, poor control of execution path and node.js table search fails with promises in use. Judging by console.log print-outs, my recursive routine works great, except that the first call to resolve() (a signal to the nth recursive call) gives the green light to follow-on code that shouldn't get that green light until the first call to the recursive routine calls resolve(). It turns out the first call to the recursive routine delivers the answer I want reported, but by the time it reports it, the follow-on code is no longer listening for it and is running blissfully along with an "undefined" answer. Bad.
My code is much to long to share here. I tried to write a small model of the problem, but haven't found the combination of factors to replicate the behavior.
Sound familiar? How do you keep proper control over Promises releasing follow-on code on time?
I thought maybe the first call to the routine could start an array passed into a Promise.all and later calls would add another entry to that array. I haven't tried it. Crazy?
Without seeing your actual code, we can't answer specifically.
Sound familiar? How do you keep proper control over Promises releasing
follow-on code on time?
The answer is always to not resolve the first promise in the chain until you're ready for things to execute and to structure your promise chain so that dependent things don't get executed until the things they are waiting on have been properly resolved. If something is executing too soon, then you're either calling something too soon or your promise structure is not correct. Without seeing your actual code, we cannot know for sure.
A common mistake is this:
someAsyncOperation().then(someOtherAync()).then(...)
which should be:
someAsyncOperation().then(someOtherAync).then(...)
where you should pass a reference to the next async function rather than calling it immediately and passing its return value.
I thought maybe the first call to the routine could start an array
passed into a Promise.all and later calls would add another entry to
that array. I haven't tried it. Crazy?
You cannot pass an array to Promise.all() and then add things to the array later - that is not a supported capability of Promise.all(). You can chain subsequent things onto the results of Promise.all() or do another Promise.all() that includes the promise from the previous Promise.all() and some more promises.
var someArrayOfPromises = [...];
var pAll = Promise.all(someArrayOfPromises);
var someMorePromises = [...]
someMorePromises.push(pAll);
Promise.all(someMorePromoises).then(...)

JavaScript Promises and race conditions

I just started using Promises in JavaScript using the Q library. I am running into a race condition and am wondering what would be the best way to resolve it.
The problem is that Q always calls the callbacks using process.nextTick() (also mentioned in the Promises/A+ spec) which means that I might miss some state changes in the object in the time between the resolution of the promise and the time the callbacks are called. My concrete problem is that I have an incoming connection and am missing the first messages. Messages are distributed using EventEmitter.
The code looks something like this. It uses the palava-client (but the problem should be universal) and is written in CoffeeScript:
defer = q.defer()
session.on 'peer_joined', (peer) ->
defer.resolve(peer)
return defer.promise
And somewhere else
peer_promise.then (peer) ->
peer.on 'message', (msg) ->
console.log "Message received:", msg
The first messages sometimes are lost because they got emitted before the promise ever got notified. The problem does not occur using only EventEmitter and Callbacks because the callbacks are always called immediately blocking the JavaScript Thread from handling the incoming messages.
The following code never misses messages:
session.on 'peer_joined', (peer) ->
peer.on 'message', (msg) ->
console.log "Message received:", msg
Do you see any way I can solve the problem using promises? I really would like to keep using them in my abstraction layer to ensure that only one peer is accepted. Is there any other way to avoid such race conditions?
As someone who usually promotes using promises, my suggestion is:
Do not use promises here
Promises represent one time events. They are an abstraction over values, one a promise changes its state it can no longer be changed. A promise starts off as pending and changes state once to either fulfilled or rejected.
You are facing a scenario where you have many users, each user joins and needs to add events, the users might 'go away', your scenario simply doesn't describe the same linear flow promises excel at. Promises are useful for a certain scenario - they are not for every concurrency problem. Using an event-emitter here is perfectly appropriate.
Your case (a user joining) does not really represent a resolved proxy operation. The code that "doesn't miss messages" is indeed more correct.
If you still choose to use promises here
There are a few things you can do:
You can use Q's progression events and add a progress handler in the creation phase. Note that Kris (Q's author) has called progression broken, and it is being removed in the next version of Q. I recommend against it.
You can wrap the message callback to only fire once a handler has been attached - accumulate items fired with a handler when it is created (in an array) and then trigger them all when the message handler is added (after you resolve, in a .then on the deferred you return.

Categories

Resources