Understanding Object Identification

Applies to TestLeft 15.40, last modified on March 17, 2022

TestLeft sees applications as a set of objects organized in a tree structure. You can see this structure in the UI Spy.

Test object model for Notepad

Click the image to enlarge it.

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.

Example: Desktop application

Example: Web application

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).

Example: Desktop application

Example: Web application

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:

  1. 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.

  2. Select an object in UI Spy and then click Copy Identification to generate code to the clipboard.

    Generating code to search for an object
  3. 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.

Example

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.

See Also

Object Identification
About Driver Objects

Highlight search results