Introducing JavaScript Execution on InternetExplorer and CrossBrowser in Coded UI Test

Introducing JavaScript Execution on InternetExplorer and CrossBrowser in Coded UI Test

  • Comments 11

This blog assumes that you have a prior understanding of Coded UI Test and some experience with Recording and Playback on either Internet Explorer or Cross Browser.  A good starting point for Cross Browser testing would be here. This blog explains the new “JavaScript Execution" capability of the Coded UI test on Internet Explorer as well as Cross Browser that we added in VS Update 2. 

With Update 2, Users will be able to run JavaScripts on the webpages they are testing. This will help the users in achieving certain complex actions or using custom controls that are otherwise difficult or entirely not possible due to the limitations of the web browser or coded ui test or any other issues. This API will also serve as an alternative to the actions that take relatively long time to execute in comparison with running a simple JavaScript. It might also simplify the test code if multiple steps are required in achieving the desired effect without JavaScript..

Supported Versions:                                                                                                                                  

  1. IE version - IE9/ classic IE10 
  2. Firefox version - 15+
  3. Chrome version - 21+
  4. Visual Studio Ultimate/Premium - VS 2012 RTM  + VS 2012 Update 1 +  VS 2012 Update 2
  5. Selenium NET Bindings and the Selenium ChromeDriver made available to you through an installer on Visual Studio Gallery.

API Definition and Usage:

Upon Installation of the VS Update 2, this feature will automatically be available as API  (mentioned below) in BrowserWindow Class.

object ExecuteScript(string script, params object[] args)

I hope that the readers of this blog are already acquainted with the BrowserWindow Class. BrowserWindow class is the type of the window objects that get generated if you record on internet explorer using Coded UI Test. You can refer to the Cross Browser Scenario videos mentioned in this link  for Firefox or Chrome. If you are either using coded ui test builder to generate code or hand coding the test, then you should have access to the window object of the browser, which is of type BrowserWindow. For Handcoding coded UI Tests, you can refer to this blog.

You can call the "ExecuteScript" method using the window object. ExecuteScript takes the script as first argument and any optional arguments to the script, if any. If there is a return value expected, then the API will return that value, otherwise it will return null. 

Script Syntax:

Script Syntax follows the ECMA standards and no further editing is required. However, if you want to return a value from the script, you will have to use the return keyword at the end of the script. If you add a return at the middle of script, then any script code after the return value statement will not be executed. Reason for this behavior is due to the fact that "ExecuteScript" cannot know which value to return from the script, unless explicitly told. JavaScript can be any complex script with hundreds of lines containing variable definitions, function definitions, function calls etc. To make the decision of return value easier, "ExecuteScript" will return the value based on the return keyword. Please note that the usage of "return" keyword inside function definitions is not affected due to this.  

Script can directly call any JavaScript functons that are already defined inside the web page. Any Script errors will result in UITestJscriptExecutionException. 

Arguments Usage:

Arguments for the script can be variables that you cannot directly embed in the script or based on dynamically changing variables. Arguments types that can be sent to the API are "double", "long", "bool", "string",  "HtmlControl" or a List of objects where each object can be any one of the aforementioned types. Script should specify arguments as per ECMA standards. "ExecuteScript" supports the same return types as the argument types. we also support Nested Lists, but we suggest shallow nest depth. If an HTML element that you are trying to return is no longer available after script execution and before script can return the said control, either due to page navigation or dynamic controls, then the API will return NULL and will not throw UITestControlNotAvailableException. Reason being that the Coded UI Test cannot rollback the executed script just because of one or few controls of dynamic nature.

Example:

long result = (long) browserWindow.ExecuteScript(" return addnumbers(arguments[0], arguments[1]); " , 2, 3 );

Note the usage of return keyword so that the function result can be returned back to the test. Script will get executed as if the arguments[i] are substituted with the corresponding argument value. Any incorrect arguments or bad argument indexes will result in an UITestJscriptExecutionException.

 

Usage Examples:

All the below examples assume that "browserWindow" is the browser window object of your Coded UI Test.

Example 1 - Note here that the ExecuteScript API does not support Int, and only supports long:

long result = (long) browserWindow.ExecuteScript(" return addnumbers(arguments[0], arguments[1]); " , 2, 3 ); // result is 5

Example 2 - ExecuteScript can return the specific HtmlControls from the JavaScript and one can use them as UI Test Controls. Here, the code returns the Amazon's search box from the script and sets the text using UI Test Control APIs:

 // Launch Amazon main window using BrowserWindow.Launch
// Alternatively, launch site manually and add it to UIMap using coded ui test builder
BrowserWindow browserWindow = BrowserWindow.Launch("http://www.amazon.com");
// Get the search text box of Amazon web site using its id
HtmlEdit searchBox = (HtmlEdit) browserWindow.ExecuteScript("return document.getElementById(arguments[0])", "twotabsearchtextbox");
searchBox.Text = "Visual Studio 2012";

Example 3 - ExecuteScript can take HtmlControl as an argument:

 BrowserWindow window = BrowserWindow.Launch("http://www.bing.com");
// Here I added the Bing Search text box to my UI Map using Coded UI Test Builder
window.ExecuteScript("arguments[0].value = 'CodedUITest'", this.UIMap.UIBingWindowsInternetEWindow.UIBingDocument.UIEnteryoursearchtermCustom);

Example 4 - ExecuteScript can return nested arrays from the Script. API will return a List<object> and each object has to be typecasted by the user based on their expectations of return values:

 List<object> listOfObjects = (List<object>) browserWindow.ExecuteScript(@" var array = new Array();
array[0] = 'string';
array[1] = 20;
array[2] = document.getElementById('textbox1');
array[3] = new Array();
array[3][0] = 25.34;
array[3][1] = 'string2';
return array; ");

Example 5 - Returning custom attributes. If the webpage you are testing like the one below, then JavaScript Execution is very useful and easy to use to read any custom attributes: 

 // Launch Amazon main window using BrowserWindow.Launch
// Alternatively, launch site manually and add it to UIMap using coded ui test builder
BrowserWindow browserWindow = BrowserWindow.Launch("http://www.amazon.com");
// Amazon.com uses a custom attribute which we can read using Javascript
// <div id="nav_subcats_5" class="nav_browse_subcat nav_super_cat" data-nav-promo-id="digital-games-software" .....
string promoId = (string)browserWindow.ExecuteScript("return document.getElementById('nav_subcats_5').getAttribute('data-nav-promo-id');");

Example 6 - Using JavaScript to check Document Ready State to implement Wait logic (especially in Cross Browser Scenario):

 // Launch Amazon main window using BrowserWindow.Launch
// Alternatively, launch site manually and add it to UIMap using coded ui test builder
BrowserWindow.CurrentBrowser = "chrome";
BrowserWindow browserWindow = BrowserWindow.Launch("http://www.amazon.com");

// Create new stopwatch
Stopwatch stopwatch = new Stopwatch();

// Begin timing
stopwatch.Start();

bool isDocumentReady = false;
// Try for 3 minutes
while (!isDocumentReady && stopwatch.ElapsedMilliseconds < 120000)
{
isDocumentReady = (bool)browserWindow.ExecuteScript("return document.readyState == 'complete'");
// wait for half a second before trying again
Thread.Sleep(500);
}
if (!isDocumentReady) throw new TimeoutException();
// Continue otherwise

Limitations:

1)  If the JavaScript takes long time to execute, the ExecuteScript API will NOT timeout. Currently, CUIT does not provide any way of setting any kind of execution timeout for this API. User will have to implement his/her own way of timing the execution.

2)  "ExecuteScript" API will not return "Int" types directly even if you are expecting an Integer. User will have to cast it to "long" at first and then to "Int" if they really want "Int". See Usage Example 1.

3)  API cannot define functions in a normal way such that the user can use them later as if they are defined in the web page. User can define and call the function normally  in the same script i.e. single execution call, but cannot do it across multiple execution calls.  Our API cannot directly inject the function into the webpage, but can hold onto a function variable which can be used later to execute the function. One can use execute a function after defining it in the below fashion:

// you cannot define a function in a normal way and use it later
browserWindow.ExecuteScript("addnum = function(arg0, arg1) { return (arg0 + arg1); }; ");
long result = (long) window.ExecuteScript("return addnum(2,3)");

4) To access elements within frames, user will have to do it themselves using HTML Dom Frame/IFrame objects within the script itself. "ExecuteScript" API will not do the frame switching.

 // Launch W3C Schools frame example page using BrowserWindow.Launch
BrowserWindow browserWindow = BrowserWindow.Launch("http://www.w3schools.com/html/html_iframe.asp");

// There is another W3C Schools page embedded inside the original page
// We are retreving an inner control inside iframe
HtmlImage w3CLogoImage = (HtmlImage)browserWindow.ExecuteScript("return document.getElementsByTagName('iframe')[0].contentDocument.getElementsByTagName('img')[0];");

// Read html image width
Console.WriteLine(w3CLogoImage.Width);
Leave a Comment
  • Please add 7 and 1 and type the answer here:
  • Post
  • I have installed update 1 and update 2 but I still don't see any ExecuteMethod that return an object. Can you please tell me the assembly name and location.

  • It's working now.

  • How will the syntax look like with an online calculator (www.athropolis.com/.../calc.htm). For example, 2 + 2 = 4.

  • I forgot to post my code which is not working...

    BrowserWindow browser = BrowserWindow.Launch(@"www.athropolis.com/.../calc.htm");

               HtmlButton b = (HtmlButton)browser.ExecuteScript("return document.getElementsByName(arguments[0]", "btnTwo");

               Mouse.Click(b);

  • I am trying to test JavaScript Execution across browsers and the results are not uniform. Mostly IE looks good but even simple scripts to return element based on "id" are not running in firefox.

    Is there anything that we need to do different for cross browser execution of JS?

  • @CH_MN:

    your JavaScript syntax is incorrect. you are returning an array of elements from script, but trying to cast to a single object type. You should change your script to below. Also, Button is not of type HtmlButton, but it is an HtmlInputButton. this depends on how the HTML page defined the button of course.

               string script = "return document.getElementsByName(arguments[0])[0]";

               HtmlInputButton b = (HtmlInputButton)browser.ExecuteScript(script, "btnTwo");

               Mouse.Click(b);

  • @Cross Browser: As long as you installed the Cross Browser Components correctly from VS gallery, JS execution should work.

    Can you tell us the Firefox version you are using?

  • @Sai:

    THANKS! It is working perfectly. I need to brush up on my javascript ;)

  • Hello, I'm having problems running this method from my test agent, I'm running update 2 and i'm getting this:

    System.MissingMethodException: Method not found: 'Void Microsoft.VisualStudio.TestTools.UITesting.BrowserWindow.ExecuteScript(System.String)'.

  • I have VS 2012 Update 4, but I don't see any ExecuteMethod in BrowserWindow. Am I missing somehting there ?

  • Is there any way to add a javascript file on Page using BrowserWindow.ExecuteScript() or any other way in CodedUIProject so that i could write all my functions in a single js file and could include them on page wherever required.

Page 1 of 1 (11 items)