3

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?

Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118
  • What is the "Other element that would receive the click"? Can you see it on the page or look at the error message and find it in the HTML? I've had weird stuff happen where there's a tooltip or something lingering and covering up the element I'm trying to click. It's a silly problem but I've had it happens a few times. If that's not it, someone smarter than me will need to weigh in. – C. Peck Nov 08 '17 at 21:11
  • There shouldn't be any other element to receive the click at that point- that's what's confusing me here... The 'Cancel' button (`closeDlgBtn` element) that it's trying to click is on the dialog that is displayed on top of the window at the time when this should be called... – Noble-Surfer Nov 09 '17 at 09:39
  • Having said that, the error does say: ` Other element would receive the click: ` – Noble-Surfer Nov 09 '17 at 09:40
  • But that seems to indicate to me that it thinks the dialog will receive the click, but isn't expecting it to- even though that's what I intend it to do...? – Noble-Surfer Nov 09 '17 at 09:41
  • So you're saying the "other element" that it's saying would receive the click is the very same element that you're trying to click? Yikes. I'm stumped. – C. Peck Nov 09 '17 at 11:37
  • It appears that this is the case, which is why I'm so confused by the error... With the test case as it's written in the edit at the end of my OP, when I run the test, the command line shows the debug `Call to chartsMenuBtn.click() performed`, and then immediately fails straight after that... – Noble-Surfer Nov 09 '17 at 11:48
  • Although looking at it again, it maybe that it's the line `browser.actions(chartsMenuBtn.click()).perform().then(` that's failing (although since the `console.log()` statement inside that is displayed in the console, I wouldn't expect that to be the case...). But the error message does seem to indicate that it's the `Charts` button that is not clickable- although it clearly should be, since there is nothing displayed on top of the window that would prevent that menu item being clickable until the browser has navigated to the Charts page... – Noble-Surfer Nov 09 '17 at 11:52
  • Something is clearly going wrong there, but since the output shows the "other element would receive click error" Selenium must be trying to click.... ie doesn't seem like a problem with your js getting executed. Sorry I can't be more help, and sorry you're experiencing this stupid issue. – C. Peck Nov 09 '17 at 11:58
  • I tried putting a call to `browser.pause()` in just before the click on the `chartsMenuBtn` and ran my test again. It reached the 'pause' just before the `chartsMenuBtn` was clicked, and when I pressed 'c' to continue (i.e. the next action was clicking the `chartsMenuBtn`), it clicked it successfully, and navigated to that page. – Noble-Surfer Nov 09 '17 at 12:09
  • The dialog was automatically opened, but then when it proceeded to try and find the `closeDlgBtn` element, I got a message (not an error) in the console stating that: ` W/element - more than one element found for locator By(link text, Charts) - the first result will be used`. I'm guessing that this is the root of my problem, as when trying to manually continue my test from here, nothing happened- I kept getting the debug in the console, but no actions happened in the browser. I found this question: https://stackoverflow.com/questions/28464604/more-than-one-element-found-for-locator-warning – Noble-Surfer Nov 09 '17 at 12:13
  • and tried what it suggested by using: `var chartsMenuBtn = element(by.linkText("Charts")).first();` rather than `var chartsMenuBtn = element(by.linkText("Charts"));` to get the `chartsMenuBtn` element, but this gave me the error: ` TypeError: element(...).first is not a function`... Any other suggestions? No worries if not, and thanks for your help- it's much appreciated. – Noble-Surfer Nov 09 '17 at 12:15
  • Well what is the other element that it is finding? I'd assume there is another element somewhere on the page with that linkText. the `Element.first();` might work, but I'd probably rather find a more reliable locator for that element. – C. Peck Nov 09 '17 at 12:16
  • The other element it's finding appears to be the dialog- but that doesn't make sense, since the dialog is only displayed when the `Charts` page has loaded (i.e. immediately after navigating to that page). It should not be trying to click on the `chartsMenuBtn` again after it has already clicked it and browsed to that page... It seems that it may be 'starting' the click on the `chartsMenuBtn`, the browser is then navigating to the Charts page, and the dialog is opened, and then the click to the `chartsMenuBtn` is completed- by which point, the `chartsMenuBtn` is no longer clickable- – Noble-Surfer Nov 09 '17 at 13:25
  • because the dialog is now displayed on top of the page... – Noble-Surfer Nov 09 '17 at 13:25

0 Answers0