TestLeft sees applications as a set of objects organized in a tree structure. You can see this structure in the UI Spy.
Top-level objects are process and browser. Typical object hierarchies are —
process > top-level window > controls > child elements
browser > web page > web page elements > child elements
You can use the Pick Object and Point and Fix tools to select an object on screen.
To verify that the object you have selected in the hierarchy is the one you need, you can view the object’s image in the Preview section of the UI Spy panel, or you can command UI Spy to highlight the corresponding interface element in the application.
Each object has a corresponding TestLeft interface that provides automation properties and methods for that object. TestLeft includes automation interfaces for many desktop and web application technologies, including third-party controls. See Supported Technologies for the full list, and Interface and Class Reference to learn about available interfaces.
Namespaces and Packages
All test objects and types are organized in the TestLeft library according to application technologies (web, WPF, Java, and others) and vendors (DevExpress, Telerik, and so on).
In your test code, you will require namespaces (for .NET code) or packages (for Java code) that contain test objects for your application type. For example, if you are testing a .NET Windows Forms application that uses DevExpress controls, use the following:
C#
// Core namespaces:
using SmartBear.TestLeft;
using SmartBear.TestLeft.TestObjects;
// Namespaces that provide support for
// Windows Forms applications and DevExpress controls:
using SmartBear.TestLeft.TestObjects.WinForms;
using SmartBear.TestLeft.TestObjects.WinForms.DevExpress;
Visual Basic .NET
' Core namespaces:
Imports SmartBear.TestLeft
Imports SmartBear.TestLeft.TestObjects
' Namespaces that provide support for
' Windows Forms applications and DevExpress controls:
Imports SmartBear.TestLeft.TestObjects.WinForms
Imports SmartBear.TestLeft.TestObjects.TestObjects.WinForms.DevExpress
Java
// Core packages:
import com.smartbear.testleft.*;
import com.smartbear.testleft.testobjects.*;
// Packages that provide support for
// Windows Forms applications and DevExpress controls:
import com.smartbear.testleft.winforms.*;
import com.smartbear.testleft.winforms.devexpress.*;
Accessing Objects in Tests
To access a specific object in a TestLeft test, use the Find
method and provide a search pattern. A search pattern is a programmatic description of an object. It specifies unique properties and values for that object, such as the object type (button, edit, link, and so on), name assigned by the developers, and so on. The pattern class depends on your application type and object type (see the table below). The syntax looks as follows:
C#
Visual Basic .NET
Java
Typically, you can obtain a top-level object (process or browser) when starting the tested application. Then you can use the Find
method to obtain the desired child objects.
However, if you want to use an already running application or browser, you can also use the Find
method to access a top-level object (process or browser).
To get all the objects that match a search pattern, use the FindAll
method.
C#
Visual Basic .NET
Java
The method will return a sequence of objects that match the pattern. To learn more about the FindAll method, see Searching for Test Objects.
Search Depth
The Find
and FindAll
methods have an optional parameter for the search depth. The search depth is relative to the parent object as seen in the UI Spy (1 = immediate child objects, 2 = child objects + their child objects, and so on). This allows you to skip intermediate objects so that instead of —
C#
IWebElement panel = page.Find<IWebElement>(new WebElementPattern()
{
// We want to exclude this intermediate object ...
ObjectType = "Form",
idStr = "form"
}).Find<IWebElement>(new WebElementPattern()
{
ObjectType = "Panel",
idStr = "content"
});
Visual Basic .NET
Dim panel As IWebElement = page.Find(Of IWebElement)(New WebElementPattern() With {
.ObjectType = "Form", ' We want to exclude this intermediate object...
.idStr = "form"
}).Find(Of IWebElement)(New WebElementPattern() With {
.ObjectType = "Panel",
.idStr = "container"
})
Java
WebElement panel = page.find(WebElement.class, new WebElementPattern() {{
ObjectType = "Form"; // We want to exclude this intermediate object...
idStr = "form";
}}).find(WebElement.class, new WebElementPattern() {{
ObjectType = "Panel";
idStr = "container";
}});
— you can use —
C#
IWebElement panel = page.Find<IWebElement>(new WebElementPattern()
{
ObjectType = "Panel",
idStr = "content"
}, 2); // Search depth
Visual Basic .NET
Dim panel As IWebElement = page.Find(Of IWebElement)(New WebElementPattern() With {
.ObjectType = "Panel",
.idStr = "container"
}, 2) ' Search depth
Java
WebElement panel = page.find(WebElement.class, new WebElementPattern() {{
ObjectType = "Panel";
idStr = "container";
}}, 2); // Search depth
Generating Code Using UI Spy
TestLeft can automatically generate the code to search for objects:
-
If needed, click on the UI Spy panel and configure the code generation settings. You can select an object (the Driver object, a process or browser, a top-level window or web page) starting from which the generated code will search for the needed object.
-
Select an object in UI Spy and then click Copy Identification to generate code to the clipboard.
-
Paste the code to your test.
The generated code can be long, because it includes code for intermediate objects in the hierarchy. Always review and tweak the generated code:
-
Remove intermediate objects that do not have unique properties, such as web Panels without IDs. Remember to add or increase the search depth in
Find
calls that precede the deleted snippets. -
Introduce variables to store objects you want to re-use.
-
Add more identification properties to make search conditions unique.
-
Add the search depth if needed.
Using Custom Properties in Search Patterns
Search pattern initializers include only a few common properties, but you can add custom properties by using the Add
method:
C#
IWebElement searchbox = parentObject.Find<IWebElement>(new WebElementPattern()
{
ObjectType = "TextBox"
}.Add("class", "form-control-search").Add("parent.idStr", "search-small")
);
Visual Basic .NET
Dim searchbox As IWebElement = parentObject.Find(Of IWebElement)(
New WebElementPattern() With {
.ObjectType = "TextBox"
}.Add("class", "form-control-search").Add("parent.idStr", "search-small")
)
Java
WebElement searchbox = parentObject.find(WebElement.class, new WebElementPattern() {{
ObjectType = "TextBox";
}}.add("class", "form-control-search").add("parent.idStr", "search-small")
);
This syntax is equivalent to:
C#
WebElementPattern pattern = new WebElementPattern()
pattern.ObjectType = "TextBox";
pattern.Add("class", "form-control-search");
pattern.Add("parent.idStr", "search-small");
IWebElement searchbox = parentObject.Find<IWebElement>(pattern);
Visual Basic .NET
Dim pattern As WebElementPattern = New WebElementPattern()
pattern.ObjectType = "TextBox"
pattern.Add("class", "form-control-search")
pattern.Add("parent.idStr", "search-small")
Dim searchbox As IWebElement = parentObject.Find(Of IWebElement)(pattern)
Java
WebElementPattern pattern = new WebElementPattern();
pattern.ObjectType = "TextBox";
pattern.add("class", "form-control-search");
pattern.add("parent.idStr", "search-small");
WebElement searchbox = parentObject.find(WebElement.class, pattern);
This way you can search by —
- any properties listed in the UI Spy
- nested properties like
parentNode.tagName
- the
CustomObjectType
property that the test engine adds to web elements implemented with the Web Components specifications - custom HTML attributes like
ng-*
attributes in AngularJS
Using Wildcards
You can use wildcards in string property values in search patterns to mask dynamic parts of the value.
Wildcard | Description |
---|---|
* | A string of any length or an empty string. To specify the * character literally, use **. |
? | Any single character or no character. |
Wildcard search is enabled by default, so there is no additional configuration involved.
C#
ITopLevelWindow wndNotepad = notepad.Find<ITopLevelWindow>(new WindowPattern()
{
// Match "Untitled - Notepad", "MyFile.txt - Notepad", and so on
WndCaption = "* - Notepad"
});
Visual Basic .NET
Dim wndNotepad As ITopLevelWindow = notepad.Find(Of ITopLevelWindow)(New WindowPattern() With {
.WndCaption = "* - Notepad"
})
' Matches "Untitled - Notepad", "MyFile.txt - Notepad", and so on
Java
TopLevelWindow wndNotepad = notepad.find(TopLevelWindow.class, new WindowPattern() {{
WndCaption = "* - Notepad";
}});
// Matches "Untitled - Notepad", "MyFile.txt - Notepad", and so on
Using Regular Expressions
You can use regular expressions in string property values in the search patterns. TestLeft regular expressions are strings in the "regexp:expression" format, for example, regexp:gr[ae]y
. For the supported tokens, see Regular Expression Syntax.
C#
IGridView grid = mainForm.Find<IGridView>(new WinFormsPattern()
{
WinFormsControlName = "regexp:^grid\d+$"; // grid1, grid2, grid15 and so on
}, 5);
Visual Basic .NET
Dim grid As IGridView = mainForm.Find(Of IGridView)(New WinFormsPattern() With {
.WinFormsControlName = "regexp:^grid\d+$" ' grid1, grid2, grid15 and so on
}, 5)
Java
GridView grid = mainForm.find(GridView.class, new WinFormsPattern() {{
WinFormsControlName = "regexp:^grid\\d+$"; // grid1, grid2, grid15 and so on
}}, 5);
Regular expressions in search patterns are always case-sensitive.
TestLeft searches for a partial match unless the regular expression contains the ^ (the beginning of a line) or $ (the end of a line) anchors. For example, regexp:hello
is the same as regexp:.*hello.*
and matches any string containing hello
, but regexp:^hello$
matches the exact hello
string.
Using XPath and CSS Selectors
In web applications, you can use FindChildByXPath
and QuerySelector
to find objects by XPath 1.0 expressions and CSS selectors.
C#
IWebElement textbox = page.FindChildByXPath<IWebElement>("//input[@name='q']");
IWebElement link = page.QuerySelector<IWebElement>("#lst-ib");
Visual Basic .NET
Dim textbox As IWebElement = page.FindChildByXPath(Of IWebElement)("//input[@name='q']")
Dim link As IWebElement = page.QuerySelector(Of IWebElement)("#lst-ib")
Java
WebElement textbox = page.findChildByXPath(WebElement.class, "//input[@name='q']");
WebElement link = page.querySelector(WebElement.class, "#lst-ib");
Which Pattern Class Do I Use?
The search pattern class depends on the application technology (web, WinForms, WPF, and so on) and object type. Some pattern classes are shared among all objects of a technology. For example, WPFPattern
applies to all WPF controls – text boxes, buttons, and so on.
Object Type | Search Pattern Class | Namespace | |
---|---|---|---|
Desktop |
|||
Process | ProcessPattern |
SmartBear.TestLeft.TestObjects |
|
Objects in standard Windows applications | WindowPattern |
SmartBear.TestLeft.TestObjects |
|
.NET WinForms objects | WinFormsPattern |
SmartBear.TestLeft.TestObjects.WinForms |
|
WPF objects | WPFPattern |
SmartBear.TestLeft.TestObjects.WPF |
|
Delphi & C++Builder objects | VCLPattern |
SmartBear.TestLeft.TestObjects.VCL |
|
VCL.NET objects | VCLNETPattern |
SmartBear.TestLeft.TestObjects.VCLNET |
|
Java AWT & Swing objects | AWTPattern |
SmartBear.TestLeft.TestObjects.Swing |
|
Java SWT objects | SWTPattern |
SmartBear.TestLeft.TestObjects.SWT |
|
JavaFX objects | JavaFXPattern |
SmartBear.TestLeft.TestObjects.JavaFX |
|
Qt objects | QtPattern |
SmartBear.TestLeft.TestObjects.Qt |
|
Visual Basic 6 objects | VBPattern |
SmartBear.TestLeft.TestObjects.VB |
|
Web & RIA |
|||
Browser | WebBrowserPattern |
SmartBear.TestLeft.TestObjects.Web |
|
Web page | WebPagePattern |
SmartBear.TestLeft.TestObjects.Web |
|
Web page elements | WebElementPattern WebCellElementPattern (for table cells only)
|
SmartBear.TestLeft.TestObjects.Web |
|
Flash and Flex objects | FlashPattern |
SmartBear.TestLeft.TestObjects.Flash |
|
Silverlight objects | SlPattern |
SmartBear.TestLeft.TestObjects.Silverlight |
|
Browser UI elements (like tab buttons and custom Firefox toolbars) |
WebBrowserUIPattern |
SmartBear.TestLeft.TestObjects.Web |
|
Additional Technologies |
|||
MSAA | MSAAPattern |
SmartBear.TestLeft.TestObjects.MSAA |
|
UI Automation | UIAPattern |
SmartBear.TestLeft.TestObjects.UIAutomation |
|
Text Recognition | TextPattern |
SmartBear.TestLeft.TestObjects.TextRecognition |
All the patterns belong to the com.smartbear.testleft.testobjects
package.
Object Type | Search Pattern Class |
---|---|
Desktop |
|
Process | ProcessPattern |
Objects in standard Windows applications | WindowPattern |
.NET WinForms objects | WinFormsPattern |
WPF objects | WPFPattern |
Delphi & C++Builder objects | VCLPattern |
VCL.NET objects | VCLNETPattern |
Java AWT & Swing objects | AWTPattern |
Java SWT objects | SWTPattern |
JavaFX objects | JavaFXPattern |
Qt objects | QtPattern |
Visual Basic 6 objects | VBPattern |
Web & RIA |
|
Browser | WebBrowserPattern |
Web page | WebPagePattern |
Web page elements | WebElementPattern WebCellElementPattern (for table cells only)
|
Flash and Flex objects | FlashPattern |
Silverlight objects | SlPattern |
Browser UI elements (like tab buttons and custom Firefox toolbars) |
WebBrowserUIPattern |
Additional Technologies |
|
MSAA | MSAAPattern |
UI Automation | UIAPattern |
Text Recognition | TextPattern |
Detecting Ambiguous Matches
There could be situations when several objects match the specified search criteria. Use the IDriver.Options.Debug.RuntimeChecks
property to detect whether ambiguous object recognition has occurred. To learn more, see Troubleshoot Ambiguous Matches.
Separating Object Identification Code From Tests
It may be convenient to separate the object identification code and the code that simulates user actions in your tests. You can do this by implementing object models (classes that describe the object hierarchy in a tested application). To learn more, see Mapping Test Objects.