ProtractorJS Timeout on clicking element, any suggestions?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



ProtractorJS Timeout on clicking element, any suggestions?



The Problem



I have a simple 'New Booking' button I wish to click. As shown below


<button _ngcontent-c9="" class="mat-menu-item" mat-menu-item="" role="menuitem" routerlinkactive="menu-highlight-item-left" tabindex="0" ng-reflect-router-link="/booking,create" ng-reflect-router-link-active="menu-highlight-item-left" aria-disabled="false">
New Booking
<div class="mat-menu-ripple mat-ripple" matripple="" ng-reflect-disabled="false" ng-reflect-trigger="[object HTMLButtonElement]">
</div>
</button>



Something to Note



This is a Material 2 Angular 5 Application, so every page uses and functions off of Angular.



In the past, the code I will provide further down had worked 100% every single time I ran the test without fail, which leads me to believe something else in the source code may be what causing this issue. However no additional load/spinners or popups are in the way



It has absolutely no unique attributes whatsoever, no surrounding
divs with IDs to attach to or any other way of grabbing the element.
However using my knowledge of XPath, despite the problem I managed
to find a unique locator which I believe works, as shown below.


var btnNewBooking = element(by.xpath("//*[text()='New Booking']"));



I know for a fact this should grab the element, because when I query the xpath through the ChromeDevTools it highlights the element.



The Code that originally worked


var btnNewBooking = element(by.xpath("//*[text()='New Booking']"));
btnNewBooking.click();



The Exception produced from the ProtractorJS Console


Failed: Timed out waiting for asynchronous Angular tasks to finish after 11 seconds. This may be because the current page is not an Angular application. Please see the FAQ for more details: https://github.com/angular/protractor/blob/master/docs/timeouts.md#waiting-for-angular
While waiting for element with locator - Locator: By(xpath, //*[text()='New Booking'])



What i've tried so far?



I've tried using Protractors built in Expected Conditions from the API Library they have provided this includes all of these:



1) Waiting Until the Presence of the element


var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($('#abc')), 5000);



2) Waiting Until the Visibility of the element


EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be visible on the dom.
browser.wait(EC.visibilityOf($('#abc')), 5000);



3) Waiting until the clickability of the element


var EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be clickable.
browser.wait(EC.elementToBeClickable($('#abc')), 5000);



I've also tried using Angular's own waits such as:


browser.WaitForAngular();



and also


browser.WaitForAngularEnabled();





browser.waitForAngularEnabled(false) did you tried this?
– Chellappan
Aug 8 at 14:28





It is not my code, but I have grown to like the click() method at github.com/hetznercloud/protractor-test-helper which builds in waits and retries (As well as letting you specify the time out, if you wish).
– Jeremy Kahan
Aug 9 at 5:09





@Chellappan this is brilliant and it works thank you, However it leads to the other angular elements on the proceeding pages to have errors with attempting to find/click them since it's no longer using any of the pre-built angular waits for angular page loading. I tried to combat this by resetting to browser.waitForAngularEnabled(true); but this doesn't bring it back to it's original state in handling angular page rendering. Theres already a bug raised about this last year, but it came to no solution yet stackoverflow.com/questions/42648077/…
– Taran
Aug 9 at 7:56





Your results on what @Chellappan suggested tells us the locator has not become busted over time. That is useful. I understand why you don't want to mess with the waitForAngularEnabled setting. It seems that then exploring .findElement might be the way to go. Or the whole async..await approach as suggested below.
– Jeremy Kahan
Aug 9 at 13:43




2 Answers
2



The click() method returns a promise, if you need some documentation on that you can surely read the following: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise



The Protractor/WebDriverJS "Control Flow" takes care of settling these promises. However, my team has been struggling with the synchronization not being perfect.



A solution to this issue is the actually use EC to await for the element and then settle the promise of the click by chaining


.then()



Check out this stack overflow answer: Protractor, when should I use then() after a click()



Even better?



We use the new async functions to await promises in our protractor tests. This has enabled us to refactor much of the logic and ensure a proper controlled flow. This link describes well in the Fork in the road section why a "serial" code (executes one step at a time) is the outcome of using async/await: https://ponyfoo.com/articles/understanding-javascript-async-await





This is a brilliant example thank you, however I have given the chain linking of promises a go and it availed to the same timeout result, see the improved code below... expect(btnNewBooking.isPresent()).toBe(false); element(btnBookings.click().then(function () expect(btnNewBooking.isPresent()).toBe(true); ));
– Taran
Aug 9 at 7:51





btnNewBooking.isPresent() is also a promise, try resolving that, when writing our tests I found this helpful: stackoverflow.com/questions/34811569/… stackoverflow.com/questions/27947094/…
– Achooo
Aug 9 at 13:40






We have a similar function using async/await, makes it all much cleaner. Your code could then use the expect and look like this: expect(await btnNewBooking.isPresent()).toBe(true); ...
– Achooo
Aug 9 at 13:45


expect(await btnNewBooking.isPresent()).toBe(true); ...



You should try disabling Protractor to wait for being synchronous with Angular. This can be done by browser.ignoreSynchronisation. Set it to truein your conf.js file.


browser.ignoreSynchronisation


true


conf.js





The authors at github.com/angular/protractor/blob/master/lib/browser.ts say "This property is deprecated - please use waitForAngularEnabled instead."
– Jeremy Kahan
Aug 9 at 5:02





Ah. I didn't knew that.
– demouser123
Aug 9 at 6:59





It's also an Angular Application, so this isn't something that I should do due to the number of HTTPS requests and angular page renders
– Taran
Aug 9 at 9:22






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

make 2 or more post in bootsrap

Store custom data using WC_Cart add_to_cart() method in Woocommerce 3

Firebase Auth - with Email and Password - Check user already registered