Sub-items of complex GUI components

Some components of a rich GUI, trees or tables most notably, are rather complex and can contain an arbitrary number of elements like tree-nodes or table-cells. Depending on the kind of application, these elements may themselves be GUI components (Nodes in JavaFX, DOM nodes in a web application) or just a graphical representation of some data (Swing renderer concept, SWT Tree and Table items). This is a purely technical distinction and because it makes sense, from the tester's point of view, to treat these elements uniformly as separate entities and possible targets for events. QF-Test represents such sub-items in one of two ways, either as an 'Item' node or with a special syntax.

'Item' nodes

An 'Item' is defined by two parts, the component it belongs to and an index into this component. The component is identified by the parent node of the 'Item' node. The index can be either numeric or textual. Numeric indexes start with 0. In a List, for example, the element with index 1 is the second element from the top. Plain numeric indexes are not very useful for tree-nodes, because only the visible nodes are counted. Expanding or collapsing a tree node changes the numeric indexes of all nodes below it.

A textual index refers to the element by the text that is shown in the GUI. A list-item shown as "item1" in a List component would be recorded with at textual index of "item1". The textual representation is more flexible but can cause problems if the names of the elements in a component are not unique. A textual index can also be given as a regular expression (see section 44.4). In this case, the first element found that matches the regular expression will be used.

The option Sub-item format controls the format for recording indexes.

Almost all kinds of 'Items' have only one index. The exception is the table-cell in a Table component. Since tables are two-dimensional structures, two indexes are required to refer to a table-cell. The first one, the 'Primary index', defines the column of the table and the 'Secondary index' the row.

An Item for a table cell
Figure 6.1:  An 'Item' for a table cell

Tree-nodes are also special. The hierarchic structure of a tree doesn't map well to a linear one. One reason is the dependence of the numeric index on the current expansion state of the nodes. Another reason is that many kinds of trees have nodes with non-unique names. However, when the direct and indirect parent-nodes are taken into account to work with paths instead of names, uniqueness is often restored.

QF-Test uses a special syntax to represent tree nodes. An index that starts with a '/' character is considered to be a path index. Imagine a tree that shows a file-system hierarchy. The file "/tmp/file1" could be represented flat as just "file1", possibly colliding with another "file1" in some other directory, or as the full, unique path "/tmp/file1". QF-Test also supports numeric indexes with this syntax. As a numeric index "/2/3" designates the fourth child node of the third child of the root. A mixed-format index like "/tmp/2" to get the third child of the node named "tmp" is currently not possible.

Note This special syntax makes '/' a special character for elements of tree components, so it needs to be escaped when a literal '/' character is required. See section 44.6 for details about escaping and quoting special characters.

The 'QF-Test ID' of an 'Item'

Everything that was said about the 'QF-Test ID' attribute of 'Components' in section 5.3 also applies to an 'Item's' 'QF-Test ID'. It has to be unique and can be referred to by events and similar kinds of nodes that require a component target.

When assigning an 'Item' node's 'QF-Test ID' automatically, QF-Test creates it by concatenating the containing 'Component's' 'QF-Test ID' and the index (or indexes) of the element. These kinds of 'QF-Test IDs' are expressive and typically easy to recognize. However, they are also the source of a common misunderstanding: If you want to change the index of a recorded 'Item' to point to some other element, you must not change the 'QF-Test component ID' attribute of the node that refers to it (unless you use the special syntax described in the following section). Change the 'Primary index' of the 'Item' node instead.

Special 'QF-Test ID'-syntax for direct element access
Accessing simple subcomponents

There are alternative ways to target an event on an element of a complex component that does not require creation of an 'Item' node. By using a special syntax you can specify the index of the element directly in the 'QF-Test component ID' attribute of the respective node. Instead of the 'QF-Test ID' of an 'Item' node, specify the 'QF-Test ID' of the containing 'Component' and follow it with a special separator character and the index of the element. The character that separates the 'QF-Test ID' and the index designates the format for the index:

Separator Index format
@ Textual index
& Numeric index
% Regular expression
Table 6.1:  Separators and index formats for element access

To address a table-cell with 'Primary index' and 'Secondary index' simply append another separator character and the second index. That way, the 'Primary index' and 'Secondary index' can be of different format.

Example: If your test-suite contains a 'Component' node for a Table component with the 'QF-Test ID' mytable and you want to simulate a click on table-cell in the 6th row of the column with the title "Name", create a 'Mouse event' node and set its 'QF-Test component ID' attribute to mytable@Name&5.


Almost all internal ItemResolver implementations (cf. section 49.4) allow of negative indices to start counting from the end. For example, mytable&-1&-1 addresses the last cell in the rightmost table column.

Whether it is preferable to use an 'Item' node or the special syntax depends on the situation. You can use either method as you see fit and mix them as you like. As a rule of thumb, 'Item' nodes are better suited to components with a few more or less constant elements, the columns of a Table for example, or the tabs of a TabbedPane. The special syntax is more flexible and generally preferable for indexes with variable values and for elements with varying or editable values. The option Sub-item type determines whether 'Item' nodes are created or the special syntax is used when recording. With the default value "Intelligent" QF-Test will follow the rules outlined above.

Note The special meaning of the separator characters implies that literal '@', '&' or '%' characters in element indexes need to be escaped. See section 44.6 for details about escaping and quoting special characters.

Addressing multi-level sub-items

In more complex GUI applications it is possible for items like a table cell to contain arbitrary components. Typical examples are CheckBoxes or TextFields, but it is even possible to nest tables. Such inner components can be addressed using a special multi-level item syntax.
Addressing components via QPath

Any 'QF-Test component ID' used in an event or check node, regardless of whether it already contains sub-item syntax or not, can be affixed with one or more special sub-item indexes of the form @:ClassName<idx>, where <idx> is optional. This instructs QF-Test to first resolve the target component (and possibly item) for the part of the 'QF-Test component ID' before the '@:' and therein search for visible components of class ClassName. If <idx> is specified, it is treated as a 0-based index into the list of visible candidate components. No <idx> is equivalent to <0>.

The QPath Syntax expects a generic class after the '@:'. List of generic classes can be found in the Manual section 56.1. In case the component does not have a generic representation, you should provide the full class name of the Component. For example in the case of Java FX GUI 'ImageView', 'VBox', 'GridPane', 'BorderPane' Objects are not mapped by QF-Test to any of those generic classes.

The following example addresses the 2-nd ImageView Component in the 3-rd item in a list. panelSecond.list&3@:javafx.scene.image.ImageView<1>

Addressing via XPath and/or CSS-Selectors

XPath's and also CSS-Selectors are relative powerful, standardized features to describe components into a webbrowser. (The official specification can be found here: https://www.w3.org/TR/xpath/ and https://www.w3.org/TR/css3-selectors/).

Since QF-Test 4.1.0 QF-Test is also official supporting componentrecognition via xPaths and CSS-Selectors in webtests. In order to allow the faster migration of existing web-tests of under tools towards QF-Test.

The Internet is already providing numerous tutorials on how web-components can be described by using CSS-Selectors (e.g. https://www.w3schools.com/cssref/css_selectors.asp) as well on how web-components can be described by using xpaths (e.g. https://www.w3schools.com/xml/xpath_syntax.asp). In this respect the basics of this componentrecognition technics didn't get included into this manual.

Usage in QF-Test ID

Assumed that QF-Test should recognize a webcomponent via it's X-Path "$(xpath)" or it's css-selector "$(css)", the recognition can happen by using multiple ways. The most often most easiest/fastest way is to specify the X-Path or rather the css-selector in the "QF-Test component ID"-attribute of an arbitrarily Event-Node. Hereby the following syntax get's used:


or equivalent:


This Syntax can get nested in any order. For example with:


one can advise QF-Test to first search a component via X-Path and then to search for a subcomponent via the css-selector.

Note Please note that out of obvious reasons the @:xpath/@:css-syntax assumes that the used XPath/CSS-Syntax returns a single component. The usage of a XPath-syntax that does not return a single component, but for example an integer (Example: "count(.//input[@id!='Google'])") or a boolean (Example: "nilled($in-xml//child[1])"), may lead to unexpected behaviour.

Usage in scripts

The rc-Modul contains some function, that equally allows addressing web-components via xpath or css-selectors respectively.

com = rc.getComponent("genericHtml") # or rc.getComponent("genericDocument")
res = com.getByXPath(rc.lookup("xpath"))    # find subcomponent via xpath
res = com.getByCSS(rc.lookup("css"))        # find subcomponent via css
res = com.getAllByXPath(rc.lookup("xpath")) # find all subcomponent via xpath
res = com.getAllByCSS(rc.lookup("css"))     # find all subcomponent via css
Example 6.1:  Find Components via xpath / css-selectors in scripts

In order to use an XPath that does not return component(s) please use the evalJS-function:

node = rc.getComponent('genericDocument')
print node.evalJS("""document.evaluate("count(.//input[@id='Google'])",
    document, null, 0, null).numberValue;""")
Example 6.2:  Example usage for an XPath-Selector that does not return component(s)

Usage in component nodes

Within component-nodes QF-Test can equally get advised to recognize components via X-Path or css-selectors. Therefor one is specifying an additional recognition-feature below "Extra features" that is looking like:

StateMust match
Value@:xpath=${quoteitem:$(xpath)} or @:css=${quoteitem:$(css)}
Figure 6.2:  Extra Feature attributes for x-path or css-selector component recognition.
Activating item recording for web tables

Within web pages, tables are used both for 'real' visible tables and for invisible layout purpose. Also nested tables are possible. QF-Test typically cannot know where a real table starts, and therefore item based recording is not possible without further information.

Hence this information can be provided by the user. By use of the procedure qfs.web.table.recording.activateItemRecording from the standard library item recording can be activate for a given web table.

In case you don't know which QF-Test component ID to provide to the procedure, simply record a click to an arbitrary table cell. Jump to the respective component node by pressing [Ctrl-W] or right-clicking and selecting »Locate component« and look for the next node with the class name Table upwards in the component hierarchy. That should be the one to use.

NoteWhen using one of the AJAX toolkit resolvers you typically don't have to do any separate activation. AJAX tables are handled by the resolver.