Avatar of Yann Spöri
Author: Yann Spöri
01. April 2019

Accessing sub-items of GUI components

In most cases we are dealing with more or less straight-forward GUI components, such as buttons and text fields. Nevertheless we often have to deal with more complex GUI components like trees, tables and lists too. These GUI components have sub-items. For example the GUI component "Table" consists out of different table cells (=the sub-items of the table):

[Translate to English:] Tabelle

QF-Test provides multiple ways to access sub-items of GUI components:

Using the "QF-Test component ID" to specify the wanted sub-item

In the "QF-Test component ID" attribute it is possible to specify that an action should be replayed on the sub-item of a GUI component. In order to do so an identifier is added to the component id. This identifier may either be numerical (represented via the character &), textual (represented via the character @) or the identifier may be a regular expression (represented via the character %).

Examples

List or comboboxes

You only need one identifier to describe a sub-item in a list or a combobox:

[Translate to English:] ComboBox

As can be seen, the above combobox has 4 different sub-items. The sub-item "- no special model -" (with the numerical index 0), "Gomera" (with the numerical index 1), "Jazz" (with the numerical index 2) and the sub-item "Luxus" (with the numerical index 3). So either "qftestIdOfComboBox@Jazz" or "qftestIdOfComboBox&2" will access the sub-item "Jazz" in this combobox. Alternatively we can also use "qftestIdOfComboBox%J.*" - as "J.*" is a regular expression that is matching the sub-item "Jazz".

And in order to access the sub-item "Gomera" we can use:

[Translate to English:] Beispiel für ein Unterelement

Tables

In the case of a table two identifiers are needed. The first identifier is specifying the column and the second identifier the row of the wanted cell. So if we have the following table:

 

An action on the QF-Test component ID "qftestIdOfTable@Price%.*12.*" will target the cell that contains the text "$12,300.00". The same cell gets targeted by the QF-Test component ID "qftestIdOfTable@Price&0".

Trees

In order to access sub-items in a tree, we need an identifier that is taking into account the hierarchical framework of this GUI component. So if we have the following tree:

the sub-item "Mats" can be accessed via:

  • qftestIdOfTree@/Information/Accessories/Mats
  • qftestIdOfTree&/0/0/2
  • qftestIdOfTree%/Inf.*/Acc.*/M.*
  • qftestIdOfTree%/.*/.*/Mats

(and via other regular expressions). However it will not work to access the sub-item Mats via the QF-Test component ID "qftestIdOfTree%/.*/Mats". This is because with "%/.*/Mats" we are advising QF-Test to search a sub-item matching the regular expression ".*" on the first level of the tree. In this example there is only one first level sub-item ("Information"). The regular expression provided to QF-Test (".*") is matching this sub-item. QF-Test will then go on and use the next regular expression ("Mats") in order to search through the child nodes of any matching node ("Accessories", "Description"). As can be seen, both strings are not matching the desired regular expression, so "%/.*/Mats" does not work.

Using item nodes to specify the wanted sub-item

Item nodes provide the same functionality, namely to specify the wanted sub-item by index, name or regular expression. However these item nodes are used less commonly:

You can insert these nodes over the menubar (Insert → Component nodes → Item) as child nodes of any list, table or tree component node (or more general every node representing a component that supports sub-items):

The text specified in the "QF-Test ID" attribute of this node (GomeraItemInComboBox in the given example, but you can use nearly any other text as well) can then be used in the "QF-Test component ID" attribute of a mouse event node (or any other event replaying node). When such an event node gets executed, QF-Test will first determine the wanted GUI component via the component recognition information provided by the parent node of the inserted item node. Then QF-Test will determine the wanted sub-item by the information provided in the inserted item node. Once this is done, the desired action will be replayed on that sub-item.

QPath

Sometimes we need to access sub-components that are located within sub-items of any GUI component. This may (for example) be a button or a checkbox located inside a table cell. In order to access these subcomponents, we can use the "@:ClassName"-syntax (the so called QPath syntax). For example, if we have a button located inside a table cell, we can access it via: "qfcomponentIdOfTheTable@columnname@rowname@:Button<0>".

XPath and CSS Selectors

When you are testing a web-application it is also possible to use an XPath or CSS-Selector

in order to access the wanted GUI component and/or sub-item. As XPath and CSS selectors have been proven to be relatively difficult to write they are normally not my first choice. However this feature is nevertheless quite useful when it comes to rewriting already existing Selenium webtests into QF-Test.

The general syntax in order to use an XPath/CSS selector inside a "QF-Test component ID" attribute of an event node is:

  • genericHtml@:xpath=${quoteitem:yourXPathGoesHere}
  • genericHtml@:css=${quoteitem:yourCSSSelectorGoesHere}

Alternatively it is possible to specify an xpath and/or css selector in the extra features of a component node (or in SUT scripts). This can be done via a "Must match" extra feature with the name "qfs:item" and the value "@:xpath=${quoteitem:yourXPathGoesHere}". (In case you want to use a css-selector use "@:css=${quoteitem:yourCSSSelectorGoesHere}" as value.)

Notes

  • 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 behavior.
  • If you know what you are doing, you can nest multiple xpath/css-selector statements. For example: genericHtml@:xpath=${quoteitem:firstXPath}@:xpath=${quoteitem:secondXPath}
  • For those of you who are wondering what the "genericHtml" part in the string genericHtml@:xpath=${quoteitem:yourXPathGoesHere} means. This substring is referring to the "genericHtml" component node that is specified in the qfs.qft.
  • The used XPath is searching for the wanted component from this GUI component onwards.

Examples

Let's assume you have a single text input field on your website that is implemented via:

<input type="text" ... additional attributes ... />

XPath within a QF-Test component ID

In event nodes it is possible to address the text input field (in the above sample website) via the QF-Test component ID "genericHtml@:xpath=${quoteitem:.//input}".

CSS-Selector within a QF-Test component ID

In event nodes it is possible to address the text input field (in the above sample website) via the QF-Test component ID "genericHtml@:css=${quoteitem:input}".

XPath within a QF-Test component node

The following image show an example component node that is specifying an XPath in its extra features:

Once this component node got inserted as a sub-children of the "Windows and components" node, it is then possible to use the string "myXPathEle" (or whatever got specified in the "QF-Test ID" of this component node) in the "QF-Test component ID" attribute of event nodes.

XPath and/or CSS Selectors within SUT Scripts

In order to use an xpath in a SUT script, the following statements can be used:

 

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

Further reading

New comment
( Will be displayed on the page )
( Will not be displayed on the page )

0 comments

You have new topics in mind?
Please share them with us via blog@remove-this.qfs.de or within the comments.