I am developing a suite of tests for an AngularJS application, and have recently added the following test script to my spec.js
file:
it('should navigate to the Charts page', function() {
console.log("Start Charts page test ");
browser.waitForAngularEnabled(false);
browser.wait(EC.presenceOf(chartsMenuBtn), 5000).then(
browser.actions().mouseMove(chartsMenuBtn).perform().then(
chartsMenuBtn.click().then(
browser.wait(EC.elementToBeClickable(closeDlgBtn)).then(
function(){
closeDlg();
expect(browser.getCurrentUrl()).toBe(VM + '/#/charts');
}
)
//)
)
)
)
})
Currently, when I run my tests, all of the tests written before this one run & execute correctly, then when this test is run, I get the following output in the command line where I'm running protractor conf.js
:
...Alarms page test completed
.Start Charts page test
FA Jasmine spec timed out. Resetting the WebDriver Control Flow.
A Jasmine spec timed out. Resetting the WebDriver Control Flow.
Start final Browser page test
Browser menu button clicked
End Browser page test (then call) .
Failures:
1) App should navigate to the Charts page
Message: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. Stack: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. at ontimeout (timers.js:386:11) at tryOnTimeout (timers.js:250:5) at Timer.listOnTimeout (timers.js:214:5)
Message: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. Stack: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL. at ontimeout (timers.js:386:11) at tryOnTimeout (timers.js:250:5) at Timer.listOnTimeout (timers.js:214:5)
6 specs, 1 failure
Finished in 64.989 seconds
In the browser window that is opened by the script (the window where the tests are being run), I can see that the chartsMenuBtn
element is highlighted (i.e. when the test moves the cursor to it), but at that point, the script appears to freeze, and the call to chartsMenuBtn.click()
never appears to be run...
If I add a call to browser.pause()
into my script, so that I manually have to tell the script to continue at every executable line, then the script behaves exactly as I expect, and everything passes.
But when I remove the call to browser.pause()
, and watch the script run through on its own, it always gets stuck at the same point.
It's clear that the line:
browser.actions().mouseMove(chartsMenuBtn).perform().then(
is executed, because I can see that the chartsMenuBtn
element is highlighted in the browser. But for some reason, the script never then seems to execute the line:
chartsMenuBtn.click().then(
If it did, I would expect the browser to navigate to the Charts page (as it does if I manually click on the chartsMenuBtn
element.
The DEFAULT_TIMEOUT_INTERVAL
is set to 35 seconds in jasmine.js
with:
j$.DEFAULT_TIMEOUT_INTERVAL = 35000;
I tried increasing its value, but that didn't make a difference- the test still timed out in the same place, for the same reason, which would indicate to me that there is another reason that this test is failing/ timing out.
Does anyone have any suggestions how I can fix this?
Edit
So I changed my script to add some debug to the test (print statements before and after the call to chartsMenuBtn.click().then(
, to see whether or not this line was actually being run, and when I run my test now, I can see both of those print statements displayed in the command line:
Started
...Alarms page test completed
.Start Charts page test
Cursor hovering over chartsMenuBtn
Call to chartsMenuBtn.click() performed
FA Jasmine spec timed out. Resetting the WebDriver Control Flow.
A Jasmine spec timed out. Resetting the WebDriver Control Flow.
Start final Tag Browser page test
Tag Browser menu button clicked
End Tag Browser page test (then call)
.
The two debug lines I added were:
Cursor hovering over chartsMenuBtn
Call to chartsMenuBtn.click() performed
I added these debug lines either side of the call to:
chartsMenuBtn.click().then(
so it's clear that this line is being run, yet for some reason, the click either doesn't seem to be registering, or the result of a click on this element is not actually performing the required & expected action.
Any suggestions for why this is?
Edit
So I've managed to make a bit of progress with this, although it's still not working as I intended/ hoped... I've altered the test script slightly by putting the call to chartsMenuBtn.click()
inside a browser.actions()
call, chaining multiple promises together:
it('should navigate to the Charts page', function() {
console.log("Start Charts page test ");
browser.waitForAngularEnabled(false);
browser.wait(EC.presenceOf(chartsMenuBtn), 5000).then(
browser.actions().mouseMove(chartsMenuBtn).perform().then(
browser.actions(console.log("Cursor hovering over chartsMenuBtn ")).perform().then(
browser.actions(chartsMenuBtn.click()).perform().then(
browser.actions(console.log("Call to chartsMenuBtn.click() performed ")).perform().then(
function(){
expect(EC.visibilityOf(closeDlgBtn).call()).toBeTruthy();
}
)
)
)
)
)
})
When I now run my script again, I just get a single failure- which seems to be caused by the timing associated with animation that has been set on one of the dialogs opened during the course of one of the tests to run prior to this test.
The error states:
Failed: unknown error: Element ... is not clickable at point (40, 229). Other element would receive the click:
<div tabindex="-1" role="dialog" class="modal fade ng-isolate-scope ult-loading modal-message ng-animate in-remove in-remove-active" ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}" ng-click="close($event)" modal-window="" window-class="ult-loading modal-message" size="sm" index="0" animate="animate" style="z-index: 1050; display: block;; transition-property: opacity;transition-duration: 0.15s;">...</div>
(Session info: chrome=62.0.3202.89) (Driver info: chromedriver=2.33.506120 (e3e53437346286c0bc2d2dc9aa4915ba81d9023f),platform=Windows NT 10.0.16299 x86_64)
I tried putting the expect
clause of my test inside a browser.wait()
that would wait for the closeDlgBtn
element to be present before running (but given that my expectation is that the button element is visible, this seems a bit redundant...):
function(){
browser.wait(EC.presenceOf(closeDlgBtn), 5000).then(
expect(EC.visibilityOf(closeDlgBtn).call()).toBeTruthy();
)
}
but this gives me a syntax error stating that there's a missing )
on the line:
expect(EC.visibilityOf(closeDlgBtn).call()).toBeTruthy();
I can't see a missing )
anywhere on that line. Can anyone spot what I'm doing wrong here?
Edit
I also tried surrounding the call to browser.actions(chartsMenuBtn.click()).perform().then(
with a call to browser.wait(EC.elementToBeClickable())
, so that it would wait for the element to be clickable before clicking on it (instead of just waiting for it to be present):
browser.wait(EC.elementToBeClickable(chartsMenuBtn), 5000).then(
browser.actions(chartsMenuBtn.click()).perform().then(
browser.actions(console.log("Call to chartsMenuBtn.click() performed ")).perform().then(
function(){
expect(EC.visibilityOf(closeDlgBtn).call()).toBeTruthy();
}
)
)
)
But for some reason, I still get the same error:
Failed: unknown error: Element ... is not clickable at point (40, 229). Other element would receive the click:
which doesn't make sense- since it should be waiting for the element to be clickable before clicking on it...?
Edit
So, I had a look at actions
on the Protract API, and it appears I have been chaining the promises incorrectly. I changed the test script to:
it('should navigate to the Charts page', function() {
console.log("Start Charts page test ");
browser.waitForAngularEnabled(false);
browser.wait(EC.elementToBeClickable(chartsMenuBtn), 5000).then(
browser.actions().
mouseMove(chartsMenuBtn).
//console.log("Cursor hovering over chartsMenuBtn").
chartsMenuBtn.click().
//console.log("Call to chartsMenuBtn.click() performed").
browser.wait(EC.urlIs(VM + '/#/charts'), 5000).
//console.log("browser.wait called- URL should now be VM + /#/charts/ ").
perform()
);
})
and this seems to have resolved the 'element not clickable' issue. However, I now get another error that says:
Failed: Cannot read property 'click' of undefined
but chartsMenuBtn
has been defined with:
var chartsMenuBtn = element(by.linkText("Charts"));
Anyone have any suggestions?