7.10. Improving Object Identification

Table of Contents

7.10.1. Matching Objects with Changeable Texts
7.10.2. Exact Matching
7.10.3. Wildcard Matching
7.10.4. Regular Expression Matching
7.10.5. Real (Multi-Property) Name Properties

When Squish records tests, it uses object properties to identify most objects. For each object that Squish identifies, it creates an entry in the Object Map. Each entry is a pair of names—a symbolic name (a variable name), and a real name (a mapping of property name–value pairs). When tests are run, Squish uses the values of multi-property real names as lookup criteria when searching for objects in the AUT's memory.

Properties can be numbers, strings, or objects. For properties that have object values (i.e., the value is the name of another object, e.g., the container and window properties), another search is done using Squish's object lookup functionality to find it.

Object properties can only be matched exactly, while most string properties can use exact, wildcard, or regex matching. Some special properties also require exact matching such as type, tagName (in Squish for Web) and basetype (in Squish for Java™).

[Note]className in Squish for Web

Note that in Squish for Web the className property is unusual in that its value is a list of strings (class names) and if we use exact matching the match will work if any of the element's class attribute's classes matches the one we have specified.

7.10.1. Matching Objects with Changeable Texts

One commonly encountered problem is that many applications change the texts used by some widgets. For instance, a button's text might change from Pause to Resume and back again, or the application might put the name of the current file or workspace in the main window's title bar caption. For example, lets assume that we have the following real name for a fictional MainWindow object in our application with the title “AddressBook v1.3 - google contacts.dat”:

Python
{'windowTitle': 'AddressBook v1.3 - google contacts.dat', 'type':'MainWindow'}

This multiple property name will match the first object in the application which is of type MainWindow and whose title matches the one shown above.

Such names work perfectly well in most situations and they are generated automatically when recording a test (see Object Name Generation (Section 7.12) for more information on that topic). Unfortunately, since the windowTitle changes, this can break object names that point to it or its children.

If we wanted to make the MainWindow's real name more general, we could remove the property entirely, or use the Wildcard or the RegularExpression matching options. From the Object Map Editor, one can be selected by double-clicking on the Equals operator between the property and the value in a real name, as shown below:

Changing the matching operator in a real name property.

We can see how these object names are represented by looking at the Scripted Object Map's suite_xyz/shared/scripts/names.(py|pl|rb|tcl|js) file, as shown below:

Python
MainWindow_Wildcard = {"type": "MainWindow", "windowTitle": Wildcard("Address Book*")}
MainWindow_Regex =    {"type": "MainWindow", "windowTitle": RegularExpression("Address Book.*")}
JavaScript
export var mainWindowWildcard = {"type": "MainWindow", "windowTitle": new Wildcard("Address Book*")};
export var mainWindowRegex =    {"type": "MainWindow", "windowTitle": new RegularExpression("Address Book.*")};
Perl
our $mainwindow_wildcard = {"type" => "MainWindow", "windowTitle" => wildcard("Address Book*")};
our $mainwindow_regex =    {"type" => "MainWindow", "windowTitle" => regularExpression("Address Book.*")};
Ruby
MainWindow_Wildcard = {:type => "MainWindow", :windowTitle => Wildcard.new("Address Book*")}
MainWindow_Regex =    {:type => "MainWindow", :windowTitle => RegularExpression.new("Address Book.*")}
Tcl
set MainWindow_Wildcard [::Squish::ObjectName type MainWindow windowTitle {-wildcard {Address Book*}}]
set MainWindow_Regex    [::Squish::ObjectName type MainWindow windowTitle {-regularexpression {Address Book.*}}]

In a real world situation, you would not need both of these entries - they are equivalent. Both real names specify that the windowTitle must begin with “Address Book” followed zero or more other characters.

The Wildcard version uses * for the wildcard, and it stands for zero or more of any characters. The RegularExpression version uses dot (.) to match a single character, and star (*) as a quantity-modifying meta-character that applies to the thing before it, making it "zero or more" in quantity. These both should match “AddressBook - Untitled” and also “AddressBook - MyAddresses.adr”.

7.10.2. Exact Matching

This kind of matching can be used in all situations, and is the only kind of matching that is allowed for type and for properties whose value is an object (i.e., is specified using a real name). Here is an example:

Python
{"type": "LineEdit", "visible": 1, "buddy": {"text": "Phone:", "type": "QLabel"}}

This real name is used to identify an object of type LineEdit that has a visible set to true (1) and that has an associated label—a buddy—which in turn is specified using another real name.

7.10.3. Wildcard Matching

The Wildcard syntax is used for inexact matches. This kind of matching cannot be used for the type property or for symbolic object names.

When wildcard matching is in use the ?, *, [, ], and \ characters all take on special meanings and are not matched literally. All other characters are matched literally.

Table 7.2. The Wildcard Special Characters

?This character stands for any one single character no matter what it is
*This character stands for any number of any characters—including no characters at all
?*These two characters together stand for at least one of any character (i.e., any one single character followed by zero or more of any character)
[...]Brackets are used to specify a set of one or more characters any one of which must be matched. For example, [0-9] matches exactly one digit, and [aAbBcC] matches only an "a", "b", or "c", whether upper- or lower-case
\The backslash is used to escape one of the special characters, so \? stands for a literal "?", and \* stands for a literal "*". Unfortunately, brackets cannot be escaped so always have their special meaning, so the only way to match literal brackets is to use ? (which will match anything), or to use regex syntax


Here is a real name containing a wildcard:

Python
{'type' : 'LineEdit', 'visible':'1',
 'buddy': {'type':'Label', 'text':Wildcard("Name*\?"} }

This real name is used to identify an object of type LineEdit that has a visible property set to true (1) and that has an associated label—a buddy—which in turn is specified using another real name. But here, the buddy's label text is specified using Wildcard matching and must contain the text “Name” followed by zero or more other characters followed by a literal?”.

Here's a real name containing a RegularExpression property match:

Python
{'caption': RegularExpression('UsefulApp v[1-9].[0-9] - ?*.[dD][aA][tT]'),
 'type': 'MainWindow'}

Here, caption must have a value that starts with the literal text “UsefulApp v” followed by a digit (but not including zero), then a period, then another digit, then a space, a hyphen, and a space, and then at least one character (indicated by the ?), then zero or more other characters (due to the *), followed by “.dat” (in upper- or lower-case). Notice that if we had specified the filename part of the caption as *.[dD][aA][tT] it would have matched the suffix alone, i.e., “.dat” since the * symbol can match zero characters. By starting with the ? we ensure that at least once character is matched in front of the suffix.

7.10.4. Regular Expression Matching

The RegularExpression syntax is used for inexact matches. This kind of matching cannot be used for the type or for properties whose value is an object (i.e., is specified using another real or symbolic name). Regex matching allows us to write more sophisticated—and potentially harder to understand and maintain—matching expressions than can be achieved using wildcard syntax. For this reason, we recommend using wildcard matching where possible simply because it is easier, both to read and write.

[Note] Different Regular Expression Syntaxes

In Squish for Web editions, the regex syntax is the same as the one supported by JavaScript. Documentation for this syntax is available from Regular-Expressions.info and w3schools.com. For all other Squish editions the Qt QRegExp syntax is used—this is documented here: QRegExp.

7.10.5. Real (Multi-Property) Name Properties

Which properties does a particular object have that can be used for identifying an object? The answer is not straightforward because the properties are discovered dynamically.

To take the Qt toolkit as a typical example: Squish exposes all the object's base class's properties (i.e., QObject's properties), also any object-type-specific properties that have been added by the supplier or by the AUT (e.g., through subclassing), and finally some artificial properties that are especially useful to Squish.

In general, any of an object's properties is potentially usable for identifying it (e.g., in a real name for calls to the findObject and waitForObject functions). However, only the non-artificial properties are suitable for use in verifications (e.g., in calls to the test.compare function and other test module functions).

To find out what an object's non-artificial properties are, either look up the object's type in its toolkit's documentation, or use the Spy. To use the Spy begin by launching the AUT (see the Launch AUT action (Section 8.1.1.22)), then interact with the AUT until the relevant AUT object is visible. At this point context switch back to the Squish IDE and invoke the pick action (see the Application Objects view (Section 8.2.1)); and pick the object of interest. Now all the object's non-artificial properties will be shown in the Properties view (Section 8.2.12). To find out the object's artificial properties, invoke the context menu on the object in the Application Objects view (Section 8.2.1) and copy its real name to the clipboard: any properties in the real name that are not listed in the Properties view (Section 8.2.12) are artificial properties.

Table 7.3. Squish's Key Artificial Properties

Property NameToolkitsNotes
aboveLabelmacOS, iPhoneThe symbolic name of the label above the object being identified
aboveObjectWindowsThe symbolic name of the object above the object being identified
aboveWidgetQtThe symbolic name of the widget above the object being identified
aboveWidgetTextQtThe text held by the widget above the object being identified. Requires aboveWidgetType to also be specified.
aboveWidgetTypeQtThe type of the widget above the object being identified
basetypeJavaA more versatile alternative to type for Java toolkits
buddyQtThe symbolic name of the label associated with the object being identified
buddyNameQtThe objectName of the label associated with the object being identified
buddyTextQtThe text of the label associated with the object being identified
columnQtThe object being identified's column (if it is inside a multi-valued object such as a table or tree)
columnNumbermacOSThe object being identified's column (if it is inside a multi-valued object such as a table or tree)
containerQt, macOS, iPhone, WindowsThe symbolic name of the object that contains the object being identified
containerLabelQtThe text label of the object that contains the object being identified
containerNameQtThe name (e.g., caption) of the object that contains the object being identified
containerTypeQtThe type of the object that contains the object being identified
documentViewmacOSUsed for scrollbars (NSScroller): the symbolic name of the document view which the object being identified belongs to (i.e. the view it scrolls)
isApplicationMenuItemmacOSUsed for menu items (NSMenuItem): if this property is 1, then the menu item is the menu item in the menu bar that opens the application menu. For all other menu items, this property is 0.
leftLabelmacOS, iPhoneThe symbolic name of the label left of the object being identified
leftObjectWindowsThe symbolic name of the object to the left of the object being identified
leftWidgetQtThe symbolic name of the widget to the left of the object being identified
leftWidgetTextQtThe text held by the widget to the left of the object being identified. Requires leftWidgetType to also be specified.
leftWidgetTypeQtThe type of the widget to the left of the object being identified
nameQtThe object being identified's objectName
occurrenceQt, macOS, iPhone, WindowsA number that uniquely identifies an object which would otherwise be identical to another object (due to having exactly the same property values)
parentItemmacOSThe symbolic name of the object being identified's parent object
rightLabelmacOS, iPhoneThe symbolic name of the label right of the object being identified
rowQtThe object being identified's row (if it is inside a multi-valued object such as a list, table, or tree)
rowNumbermacOSThe object being identified's row (if it is inside a multi-valued object such as a list, table, or tree)
tableViewmacOSThe symbolic name of the NSTableView in which the object being identified belongs
typeAllThe name of the object being identified's type (or class). For most GUI toolkits this must always be present in a real (multi-property) name; however, it is not required for Squish for Windows or Squish for Web.
unnamedQtIf the object being identified does not have an objectName, this property's value is "1"; otherwise its value is "0"
visibleQt, macOS, iPhone, WindowsIf the object being identified is logically visible (i.e., not completely obscured by one or more other AUT objects), this property's value is "1"; otherwise its value is "0". In tests for native Windows applications, this property assumes the values true and false.
windowQt, macOS, iPhoneThe symbolic name of the window that contains the object being identified
windowNameQtThe name (caption) of the window that contains the object being identified
windowOccurrenceQtThe occurrence number of the window that contains the object being identified
windowTypeQtThe type of the window that contains the object being identified