Thursday, September 21Be an Automation Engineer

Execute Asynchronous Javascript in protractor

Protractor has two functions to execute javascript code in tests.

  1. executeScript
  2. executeAsyncScript

We’ve explained about executeScript with examples here.

Now, Lets know about executeAsyncScript.

browser.executeAsyncScript(Asnynchronousjavascript, args…)

Basically protractor provided this method to execute any asynchronous javascript code. We need to use this method to execute a javascript which has ajax calls or timeouts in it.

executeAsyncScript takes one or more arguments.

  1. First argument is to pass asynchronous javascript code as string or as a method.
  2. From second argument onwards we can pass different types of arguments. Supported types of elements which can be passed from second argument on wards are listed below.
    Supported arguments list:

    • boolean
    • number
    • string
    • WebElement

    Note: We can pass array or list of objects of above mentioned types.

Keep in mind: Javascript code executed with executeAsyncScript function must have a call back to inform that it’s execution has been completed. Protractor internally injects a callback function as a last argument to executeAsyncScript which can be referenced with arguments[arguments.length - 1] in the javascript code that we are passing.

var start = new Date().getTime();
browser.executeAsyncScript(
    'window.setTimeout(arguments[arguments.length - 1], 1000);').
    then(function() {
      console.log(
          'Elapsed time: ' + (new Date().getTime() - start)/1000 + ' s');
    });

In the above snippet the javascript code completes it’s execution after 1 second. It has a time out of 1 second in it.

We can also make an ajax call in executeAsyncScript. Go through the below complete example program.

describe('Execute Async Script', function () {
    it('Reddit Search', function () {
        browser.get("http://angularjs.org");
        browser.executeAsyncScript(function () {
            var callback = arguments[arguments.length - 1];
            var xhr = new XMLHttpRequest();
            xhr.open("GET", "https://www.reddit.com/search.json?q=ferrari&sort=new", true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    callback(xhr.responseText);
                }
            };
            xhr.send('');
        }).then(function (str) {
            var title = JSON.stringify(JSON.parse(str)['data']['children'][0]['data']['title']);
            title = JSON.parse(title).toString();
            console.log(title);
            element(by.model('yourName')).sendKeys(title);
            element(by.binding('yourName')).getText().then(function (welcomeText) {
                expect(welcomeText).toEqual('Hello ' + title.toString() + '!')
            });
        });
    });
});

In the above script we are calling a reddit’s public rest api and passing that response string to an input field.

Your config file will look like below:

exports.config = {
    capabilities: {
        'directConnect': true,
        'browserName': 'chrome'
    },
    framework: 'jasmine',
    specs: ['./ExecuteAsyncScript_Spec.js'],
    jasmineNodeOpts: {
        defaultTimeoutInterval: 999999
    },
   onPrepare: function () {
        browser.manage().window().setSize(1500,600);
        browser.manage().timeouts().implicitlyWait(5000);
        //This is to set the javascript async code timeout to 60 sec
        browser.manage().timeouts().setScriptTimeout(60000);
    }
};

Note:
executeAsyncScript returns a promise which will be resolved as:

  • For a HTML element, the value will resolve to a WebElement
  • Null and undefined return values will resolve to null
  • Booleans, numbers, and strings will resolve as is
  • Functions will resolve to their string representation
  • For arrays and objects, each member item will be converted according to the rules above

How to run:

protractor config.js

Happy Testing!!!

%d bloggers like this: