TestComplete allows you to execute custom JavaScript code on web pages and get its results as part of your tests. For example, if your tested web application uses a custom JavaScript framework such as jQuery, you can use the framework’s utility functions to analyze and process web page elements.
You can execute JavaScript on web pages regardless of the scripting language of your test project - VBScript, JScript, Python, DelphiScript, C++Script or C#Script. However, there are some specifics of doing this in VBScript and DelphiScript projects that are explained in this topic.
How To Execute Scripts on Web Pages
TestComplete lets you access scripts on web pages using the contentDocument.Script
property of the Page
test object. It provides access to both functions defined directly on the web page as well as in external JavaScript scripts loaded by using <script src="filename.js"/>
.
The following sections explain how you can:
-
execute application-defined JavaScript functions specified by their name,
-
execute arbitrary JavaScript expressions and statements.
Executing Application-Defined Script Functions
Application-defined script functions can be referenced directly by their name via the contentDocument.Script
object and the dot notation (in VBScript, JScript, Python and DelphiScript) or bracket notation (in C++Script and C#Script):
JavaScript, JScript
// Calling a function with no return value
pageObj.contentDocument.Script.functionName();
// Calling a function with a return value
var res = pageObj.contentDocument.Script.functionName(param1, ..., paramN);
Python
# Calling a function with no return value
pageObj.contentDocument.Script.functionName();
# Calling a function with a return value
res = pageObj.contentDocument.Script.functionName(param1, ..., paramN);
VBScript
' Calling a function with no return value
pageObj.contentDocument.Script.functionName()
' Calling a function with a return value
res = pageObj.contentDocument.Script.functionName(param1, ..., paramN)
DelphiScript
// Calling a function with no return value
pageObj.contentDocument.Script.functionName();
// Calling a function with a return value
res := pageObj.contentDocument.Script.functionName(param1, ..., paramN);
C++Script, C#Script
// Calling a function with no return value
pageObj["contentDocument"]["Script"]["functionName"]();
// Calling a function with a return value
var res = pageObj["contentDocument"]["Script"]["functionName"](param1, ..., paramN);
For example, if a web page contains the following function:
HTML, JavaScript
<script>
function sum(a, b)
{
return a + b;
}
</script>
you can call this function from your test as follows:
JavaScript, JScript
var sum = pageObj.contentDocument.Script.sum(3, 4);
Python
sum = pageObj.contentDocument.Script.sum(3, 4);
VBScript
sum = pageObj.contentDocument.Script.sum(3, 4)
DelphiScript
sum := pageObj.contentDocument.Script.sum(3, 4);
C++Script, C#Script
var sum = pageObj["contentDocument"]["Script"]["sum"](3, 4);
Note: |
Due to limitations of Chrome’s native messaging protocol, the size of parameters passed to web page scripts cannot exceed 1 megabyte. |
Executing Arbitrary JavaScript Code
To execute custom JavaScript code on a web page, you can use the following syntax:
JavaScript, JScript
pageObj.contentDocument.Script.eval("functionName()");
var res = pageObj.contentDocument.Script.eval("functionName(param1, ..., paramN)");
Python
pageObj.contentDocument.Script.eval("functionName()");
res = pageObj.contentDocument.Script.eval("functionName(param1, ..., paramN)");
VBScript
pageObj.contentDocument.Script.eval("functionName()")
res = pageObj.contentDocument.Script.eval("functionName(param1, ..., paramN)")
DelphiScript
pageObj.contentDocument.Script.eval('functionName()');
res := pageObj.contentDocument.Script.eval('functionName(param1, ..., paramN)');
C++Script, C#Script
pageObj["contentDocument"]["Script"]["eval"]("functionName()");
var res = pageObj["contentDocument"]["Script"]["eval"]("functionName(param1, ..., paramN)");
The eval
approach is useful for calling:
-
DOM methods, such as
history.back()
,location.reload()
,window.alert()
and so on:JavaScript, JScript
pageObj.contentDocument.Script.eval("history.back()");
Python
pageObj.contentDocument.Script.eval("history.back()");
VBScript
pageObj.contentDocument.Script.eval("history.back()")
DelphiScript
pageObj.contentDocument.Script.eval('history.back()');
C++Script, C#Script
pageObj["contentDocument"]["Script"]["eval"]("history.back()");
-
arbitrary JavaScript expressions:
JavaScript, JScript
pageObj.contentDocument.Script.eval("var i = 5; alert(i);");
Python
pageObj.contentDocument.Script.eval("var i = 5; alert(i);");
VBScript
pageObj.contentDocument.Script.eval("var i = 5; alert(i);")
DelphiScript
pageObj.contentDocument.Script.eval('var i = 5; alert(i);');
C++Script, C#Script
pageObj["contentDocument"]["Script"]["eval"]("var i = 5; alert(i);");
Example: Using jQuery to Find Web Page Elements
The following example uses the jQuery function $
and a CSS selector to find all links in the footer section of the main page of the SmartBear web site, http://smartbear.com.
To run this example from a keyword test, use the Run Script Routine operation.
JavaScript, JScript
function UsejQuery()
{
var url = "http://smartbear.com/";
Browsers.Item(btChrome).Run(url);
var page = Sys.Browser().Page(url);
var footerlinks = page.contentDocument.Script.$("a.footerlink");
for (var i = 0; i < footerlinks.length; i++)
Log.Message(footerlinks[i].firstChild.data, footerlinks[i].href);
}
Python
def UsejQuery():
url = "http://smartbear.com/";
Browsers.Item[btChrome].Run(url);
page = Sys.Browser().Page(url);
# Note we use the full function name - jQuery,
# because the short name $ isn't a valid identifier in Python code
footerlinks = page.contentDocument.Script.jQuery("a.footerlink");
for i in range (0, footerlinks.length - 1):
link = footerlinks.get(i);
Log.Message(link.firstChild.data, link.href);
VBScript
Sub UsejQuery
Dim url, page, footerlinks, i, link
url = "http://smartbear.com/"
Browsers.Item(btChrome).Run url
Set page = Sys.Browser.Page(url)
' Note we use the full function name - jQuery,
'because the short name $ isn't a valid identifier in VBScript code
Set footerlinks = page.contentDocument.Script.jQuery("a.footerlink")
For i = 0 To footerlinks.length - 1
Set link = footerlinks.get(i)
Call Log.Message(link.firstChild.data, link.href)
Next
End Sub
DelphiScript
procedure UsejQuery;
var url, page, footerlinks, i, link;
begin
url := 'http://smartbear.com/';
Browsers.Item[btChrome].Run(url);
page := Sys.Browser.Page(url);
// Note we use the full function name - jQuery,
// because the short name $ isn't a valid identifier in DelphiScript code
footerlinks := page.contentDocument.Script.jQuery('a.footerlink');
for i := 0 to footerlinks.length - 1 do
begin
link := footerlinks.get(i);
Log.Message(link.firstChild.data, link.href);
end;
end;
C++Script, C#Script
function UsejQuery()
{
var url = "http://smartbear.com/";
Browsers["Item"](btChrome)["Run"](url);
var page = Sys["Browser"]()["Page"](url);
var footerlinks = page["contentDocument"]["Script"]["$"]("a.footerlink");
for (var i = 0; i < footerlinks["length"]; i++)
Log["Message"](footerlinks[i]["firstChild"]["data"], footerlinks[i]["href"]);
}
Specifics of Calling Web Page Scripts
Executing JavaScript in Frames in Google Chrome
In Google Chrome, if you need to call a function defined on a web page frame, use the following syntax:
JavaScript, JScript
frameObj.contentDocument.Script.FunctionName();
Python
frameObj.contentDocument.Script.FunctionName();
VBScript
frameObj.contentDocument.Script.FunctionName()
DelphiScript
frameObj.contentDocument.Script.FunctionName();
C++Script, C#Script
frameObj["contentDocument"]["Script"]["FunctionName()"];
To execute arbitrary JavaScript code inside a frame using eval
, use the following syntax with the frame ID and double eval
:
JavaScript, JScript
frameObj.contentDocument.Script.eval("frameID.eval('var i = 5; alert(i);')");
Python
frameObj.contentDocument.Script.eval("frameID.eval('var i = 5; alert(i);')");
VBScript
frameObj.contentDocument.Script.eval("frameID.eval('var i = 5; alert(i);')")
DelphiScript
frameObj.contentDocument.Script.eval('frameID.eval("var i = 5; alert(i);")');
C++Script, C#Script
frameObj["contentDocument"]["Script"]["eval"]('frameID.eval("var i = 5; alert(i);")');
Using Parentheses in Function Calls in VBScript and DelphiScript
VBScript and DelphiScript let you omit parentheses when calling procedures and functions that do not take any parameters. However, when calling parameterless functions on web pages, do not omit parentheses:
VBScript
pageObj.contentDocument.Script.doSomething ' Incorrect!
pageObj.contentDocument.Script.doSomething() ' Correct
DelphiScript
pageObj.contentDocument.Script.doSomething; // Incorrect!
pageObj.contentDocument.Script.doSomething(); // Correct
This is because the syntax without parentheses does not execute the specified function. Instead, it returns the JavaScript Function
object corresponding to this function.
Using Arrays in VBScript, Python and DelphiScript
The VBScript, Python and DelphiScript array format is incompatible with the JavaScript array format. As a result, you cannot directly pass arrays between your VBScript or DelphiScript tests and JavaScript scripts on web pages; you should use a specific approach for this.
To pass an array as a parameter to a web page’s JavaScript function, call this function using eval
(see above). In this way, you can specify the array elements using JavaScript's array literal syntax [elem1, elem2, ..., elemN]
.
Python
pageObj.contentDocument.Script.eval("processArray([1, 2, 3])");
VBScript
pageObj.contentDocument.Script.eval("processArray([1, 2, 3])")
DelphiScript
pageObj.contentDocument.Script.eval('processArray([1, 2, 3])');
To use an array returned from the web page in your VBScript, Python or DelphiScript test, you need to convert it to the compatible array format. For this purpose, you can use the following JSArrayToVariantArray
function:
Python
# Converts a JavaScript array to a DelphiScript-compatible array
def JSArrayToVariantArray(JSArray):
arr = BuiltIn.CreateVariantArray(0, JSArray.length - 1);
for i in range (0, JSArray.length - 1):
arr[i] = aqObject.GetPropertyValue(JSArray, i);
return arr;
VBScript
' Converts a JavaScript array to a VBScript-compatible array
Function JSArrayToVariantArray(JSArray)
Dim arr(), i
ReDim arr(JSArray.length - 1)
For i = 0 To JSArray.length - 1
arr(i) = aqObject.GetPropertyValue(JSArray, i)
Next
JSArrayToVariantArray = arr
End Function
DelphiScript
// Converts a JavaScript array to a DelphiScript-compatible array
function JSArrayToVariantArray(JSArray);
var arr, i;
begin
arr := BuiltIn.CreateVariantArray(0, JSArray.length - 1);
for i := 0 to JSArray.length - 1 do
arr[i] := aqObject.GetPropertyValue(JSArray, i);
Result := arr;
end;
You can use the JSArrayToVariantArray
function as follows:
Python
arr = JSArrayToVariantArray(pageObj.contentDocument.Script.eval("getJSArray()");
VBScript
arr = JSArrayToVariantArray(pageObj.contentDocument.Script.eval("getJSArray()")
DelphiScript
arr := JSArrayToVariantArray(pageObj.contentDocument.Script.eval('getJSArray()');
The array obtained in this way is compatible with VBScript, Python and DelphiScript and can be processed using native array operations and functions of these scripting languages. For example, in VBScript you can use the LBound
and UBound
functions to determine the array’s lower and upper bounds and access array elements using the parenthesis syntax: arr(index)
.
Using Callback Functions
JavaScript supports using callback functions, that is, passing functions as arguments to other functions. For example:
HTML, JavaScript
<script>
// A sample function that takes a callback function as a parameter
function forEach(arr, callback)
{
for (var i in arr)
callback(arr[i]);
}
// Examples of using the forEach function with different callback functions
var numbers = [1, 2, 3, 4, 5];
forEach(numbers, printNumber); // specifying existing callback function
forEach(numbers, function (n) {alert(n);}); specifying callback function inline
function printNumber(n)
{
document.write(n);
}
</script>
To call such functions from your test and specify a callback function, use eval
(see above):
JavaScript, JScript
pageObj.contentDocument.Script.eval("forEach([1, 2, 3], printNumber)");
pageObj.contentDocument.Script.eval("forEach([1, 2, 3], function (n) {alert(n);})");
Python
pageObj.contentDocument.Script.eval("forEach([1, 2, 3], printNumber)");
pageObj.contentDocument.Script.eval("forEach([1, 2, 3], function (n) {alert(n);})");
VBScript
Call pageObj.contentDocument.Script.eval("forEach([1, 2, 3], printNumber)") ' Note: printNumber is a function defined on the web page
Call pageObj.contentDocument.Script.eval("forEach([1, 2, 3], function (n) {alert(n);})")
DelphiScript
pageObj.contentDocument.Script.eval('forEach([1, 2, 3], printNumber)');
pageObj.contentDocument.Script.eval('forEach([1, 2, 3], function (n) {alert(n);})');
C++Script, C#Script
pageObj["contentDocument"]["Script"]["eval"]("forEach([1, 2, 3], printNumber)");
pageObj["contentDocument"]["Script"]["eval"]("forEach([1, 2, 3], function (n) {alert(n);})");
Getting JScript Object's Properties in VBScript
When working with JScript objects and properties from a VBScript project, you may get the Object doesn’t support this property or method runtime error message. The problem occurs when you assign a value of an object’s property to the variable, and the variable name coincides with the property name but differs by case (for example, name and Name).
Suppose we have a JScript object, Obj, with a property, propertyName. Note that the property name is case-sensitive, that is:
VBScript
' The following syntax is correct
Obj.propertyName
' The following syntax is incorrect and the property value will not be returned
Obj.PropertyName
We want to get the property value to the PropertyName variable:
VBScript
' The property value will not be returned and an error will occur
Set PropertyName = Obj.propertyName
Due to VBScript specifics, if the property name coincides with the variable name, the scripting engine passes the variable name (instead of the property name) to the object. In other words, instead of getting the propertyName property, the code above will try to get the PropertyName property (which does not exist). That is why this code throws an error.
To avoid such issues, do not specify variable names that coincide with property names. The following code will work correctly:
VBScript
' The property value will not be returned and an error will occur
Set propertyNameValue = Obj.propertyName