Search code examples
angularjsseleniumasynchronousprotractortimeout

AngularJS testing with Protractor- executing asynchronous scripts


I am developing a suite of automated tests to run on an AngularJS application using Protractor. I have never used automated testing prior to working on this task, so am still quite unfamiliar with how it works/ how to implement the tests, etc.

I recently had a bit of trouble with implementing an automated click on the 'Cancel' button of a dialog that was displayed automatically when one of the tests browsed to a particular page.

I have now got the click to the 'Cancel' button working successfully, but the test script is still failing, due to an error with an asynchronous callback.

The test script is written as:

it('should navigate to the Charts page', function(done) {
    console.log("Start Charts page test");
    browser.waitForAngularEnabled(false);
    browser.actions().mouseMove(chartsMenuBtn).perform();
    chartsMenuBtn.click();
    browser.waitForAngularEnabled(true);
    //browser.sleep(5000);
    browser.call(closeDlg);
    //var closeDlgFn = closeDlg();
    //browser.wait(closeDlgFn, 5 * 1000, 'Dialog should close within 5 seconds');
    console.log("End Charts page test");
    expect(browser.getCurrentUrl()).toBe('http://192.168.1.212:8080/#/charts');
});

and the closeDlg() function called within the script is defined with:

function closeDlg(){
    browser.waitForAngularEnabled(false);
    console.log("closeDlg() function called ")
    var EC = protractor.ExpectedConditions;
    var chartConfigForm = element(by.id('chartConfigForm'));
    var closeDlgBtn = element(by.id('editGraphCancelBtn'));
    console.log("About to click closeDlgBtn ");
    closeDlgBtn.click();
    console.log("just clicked closeDlgBtn ");
    console.log("End of closeDlg() function ")
}



    browser.call(closeDlg).then(function(){console.log("End Charts page test"); done();});

When I run the script as it currently stands, I get the following output in the command line:

.Start Charts page test

End Charts page test

-- Next command: findElements

-- Next command: mouseMoveTo

-- Next command: findElements

-- Next command: clickElement

closeDlg() function called

About to click closeDlgBtn

just clicked closeDlgBtn

End of closeDlg() function -- Next command: findElements

When this is all displayed, the dialog is still currently open in the browser. As I continue to step through the test, I get the next two prompts in the command line:

-- Next command: clickElement

End Charts page test

-- Next command: executeAsyncScript

and that is when the dialog is then closed.

If I then continue to execute my test script, I get a failure:

FA Jasmine spec timed out. Resetting the WebDriver Control Flow.

A Jasmine spec timed out. Resetting the WebDriver Control Flow.

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)

5 specs, 1 failure

Finished in 260.014 seconds

Everything I have found online seems to indicate that I should increase the value of the j$.DEFAULT_TIMEOUT_INTERVAL variable in jasmine.js, which I have done- I've increased it from 10000 (default value) to 500000.

I have also added an allScriptsTimeout value in my conf.js file:

exports.config = {
    framework: 'jasmine',
    seleniumAddress: 'http://localhost:4444/wd/hub',
    specs: ['spec.js'], // List all of the different files in which the tests are defined here
    allScriptsTimeout: 120000,
    onPrepare: function() {
        browser.addMockModule('disableModalAnimations', function(){
            angular.module('disableModalAnimations', []).value('foo', 'bar');
        });
    },
    multiCapabilities: {
        browserName: 'firefox'
    }
}

I don't understand why I'm getting this timeout error?

I tried changing the call to closeDlg() in the test script to:

browser.call(closeDlg).then(function(){console.log("End Charts page test"); done();});

but still get the same error.

I doubt that the issue is actually a timeout issue, but I'm not sure about whether I am executing the asynchronous scripts correctly.

Can anyone spot what I'm doing wrong here? What is the Async callback that the error is telling me was not invoked within the timeout specified? What part of what I'm doing is asynchronous?


Solution

  • So after a lot of messing around with the code, chopping & changing, trying different approaches, and looking at various articles online for suggestions of how to do this, I finally got it working by putting the expect clause of my test inside a .then() function chained to the call to my closeDlg() function (and removing it from the it() level of the test:

    it('should navigate to the Charts page', function() {
        console.log("Start Charts page test");
        browser.waitForAngularEnabled(false);
        browser.actions().mouseMove(chartsMenuBtn).perform();
        chartsMenuBtn.click();
        browser.waitForAngularEnabled(true);
        browser.call(closeDlg).then(function(){
            expect(browser.getCurrentUrl()).toBe('http://192.168.1.212:8080/#/alarms');
    });
    

    This test now passes correctly, and following it through step by step, I can see that it executes the commands as expected, and produces the correct results.