Locating elements by multible attributes
CSS selectors by the tag and/or attribute value
CSS selectors by other attributes
Locating child elements using CSS
Locating descendant elements using CSS
Locating sibling elements with CSS
Locating n-th Element with CSS
Introduction
By default, the AI Assistant generates scenarios using smart selectors. A smart selector is a selector built based on the selector name. However, sometimes smart selectors might not work. In such cases, you will have to create your own custom selectors in TF Editor. The process is described in this article.
All examples in this article will use this very page. In order to see the html code of the page, just right-click anywhere on the article and cick Inspect in the context menu. To inspect a specific element, you can right-click on it and click Inspect in the context menu. The selected element's code will be highlighted in the inspection window. You can copy the XPath or CSS of an element in the Elements tab when you inspect an element, and then ask the AI Assistant to improve it. Read this article to find out how to do it. To check whether a selector works, you can press CTRL+F in the Elements tab and paste the selector. If it exists in the DOM, the element will be highlighted both in the page and in the DOM structure. |
There are two types of selectors supported in TestFirst: XPath and CSS. Mainly, there is one major difference between the two types of selectors. CSS selectors are unidirectional, meaning you can only move forward into the DOM (Document Object Model), but not backwards. On the other hand, XPath selectors are more universal in this regard as you can move either way from a given element. However, it is important to remember that CSS selectors work faster and are easier to evaluate.
Below you will find a comprehensive guide on how to create good selectors of both types. But first, let's look at the structure of an html element.
HTML element structure
XPath selectors
There are three main types of an XPath selector:
- absolute
- exact
- relative
Absolute XPath
An absolute XPath is the type of selector that uses the whole path to the element, from top of the document to the element.
For instance, if we want to get an absolute XPath for the search bar in the top right of this page, this would be the selector for it:
/html/body/main/div[2]/nav/div/form/input[3]
You can get this XPath by right-clicking on the element in the html document and clicking on Copy - Full XPath.
We do not recommend using absolute XPath selectors. They are extremely unstable and are very dependent on the changes in the DOM structure. Any changes made to the page where the element is located can break this kind of selector. It is highly recommended to use exact selectors where possible, and relative where exact selectors do not work for one reason or another. |
Exact XPath
An exact XPath is an XPath that uses element's own tag, attributes and/or content to locate it. In general, this is the syntax used for an exact XPath:
//tag[@attribute="attribute value"]
Following this syntax, the exact XPath for the search bar in the top right of this page will be:
//input[@type="search"]
However, in the rare cases when you do not know which tag will be used for an element at any given time, but you know an attribute, you can use a wildcard instead of a tag:
//*[@attribute="attribute value"]
Thus, with our example of the search bar it will look like this:
//*[@type="search"]
We do not recommend using the wildcard where it is avoidable. While wildcards are easier to use, using them might produce non-unique results. |
Locating elements by multible attributes
If you cannot ensure XPath uniqueness with just one attribute, you can use multiple attributes. The syntax for it is as follows:
//tag[@attribute="attribute value"][@attribute="attribute value"]
For instance, if we want to locate an element with an unknown tag that contains "user-nav" in its class, simply using one attribute wouldn't be enough since there would be two elements matching these criteria, and we'd need to use the id as well:
//*[contains(@class, "user-nav")][@id]
Functions in exact XPath
Sometimes the only way of locating an element is by the element content (the text between the opening and closing tags), or an attribute of an element can be dynamic. In such cases, functions are irreplaceable.
There are 4 main functions we can use in exact XPath selectors. In the table below you will find the description of each function as well as their syntax and examples.
Function | Description | Syntax | Example |
text() | Matches an element by inner text (case sensitive) | //tag[text()='element content'] |
If we want to find the header of this section of the article, this is the selector we would use: //h4[text()='Functions in exact XPath']
|
contains() | Matches an element by a part of attribute value (case sensitive) |
//tag[contains(@attribute, 'partial text']
|
If we want to find all panels in this article, regardless of the type of panel:
|
starts-with() | Matches an element by the starting character sequence (case sensitive) |
//tag[starts-with(@attribute, 'starting text')]
|
If we want to locate all the code blocks (pre tag) in this article that start with "//tag", this will be the selector: //pre[contains(text(), '//tag')]
|
Relative XPath
When an element has no distinctive attributes that would help you produce a unique XPath, you can use relative XPath.
Relative XPath allows you to locate an element in relation to another, known and unique element. Below you will find the syntax, description and examples of every possible relative XPath. Bur first, let's see how elements in an HTML document relate to each other.
See the sample html code snippet below:
<div>
<div>
<p>This is a paragraph</p>
<table class="info-panel" id="info-panel-1">
<tbody>
<tr>
<td>
<p>First table column</p>
</td>
<td>
<p>Second table column</p>
</td>
</tr>
</tbody>
</table>
<p>This is another paragraph<p>
</div>
<div>
Here we can see that the only element we can make a unique XPath for is the table which has a unique id. The XPath for it would be:
//table[@id="info-panel-1"]
Now, this element has a parent, a child, siblings, ancestors and descendants. In the table below you will find the description of those relationships and all elements that are in this relationship with this table.
Relationship | Description | Elements with this relationship |
Parent | An element one level above the given element | The second <div> element is the parent to our table |
Child | An element one level below the given element | The <tbody> element will be the only child element of our table |
Siblings | Elements on the same level as the given element | The two <p> elements (one above and one below the table) |
Ancestors | All elements above the given element level | Both <div> elements above the |
Descendants | All elements below the given element level | The <tbody>, <tr>, <td> elements |
Parent
There are two possible ways to get the parent of an element - using the word "parent" or using ".." notation:
//<knownXPath>/parent::*
or, if we want to specify the element tag
//<knownXPath>/parent::tag
or
//<knownXPath>/..
For instance, if I want to find the parent element of the code block in the secont row of the table in the Functions in exact XPath section of this article, these will be possible XPaths for it:
//code[contains(text(),'contains')]/parent::*
//code[contains(text(),'contains')]/parent::td
//code[contains(text(),'contains')]/..
Child
Same as with the parent, we can use different ways to locate a child element of a known element.
//<knownXPath>/child::*
//<knownXPath>/child:tag
//<knownXPath>/*
//<knownXPath>/tag
For instance, if we want to locate the TestFirst logo on top of this page, these are the XPaths we can use:
//a[@title="Home"]/child::*
//a[@title="Home"]/child::img
//a[@title="Home"]/*
//a[@title="Home"]/img
Siblings
We can locate both the preceding and the following siblings of an element. In order to do that, we need to use the preceding-sibling
and following-sibling
keywords, like this:
//<knownXPath>/preceding-sibling::*
//<knownXPath>/preceding-sibling::tag
//<knownXPath>/following-sibling::*
//<knownXPath>/following-sibling::tag
For instance, if we want to locate the paragraph elements after the Relative XPath header, this would be the XPath for it:
//h3[text()="Relative XPath"]/following-sibling::p
Similarly, we could locate the preceding paragraphs:
//h3[text()="Relative XPath"]/preceding-sibling::p
The sibling relative XPath is highly unreliable as it is very difficult to ensure its uniqueness. In most cases, it will result in multiple matches. For that reason, this type of XPath should only be used when unavoidable. |
Ancestors
We can locate all ancestors of an element using the ancestor
keyword.
//<knownXPath>/ancestor::*
//<knownXPath>/ancestor::tag
For instance, if we want to locate all ancestors of a table cell with the word "Siblings" as its content, this would be the XPath:
//td[text()="Siblings"]/ancestor::*
Please note that this is a greedy selector. It will locate all elements in the DOM that contain the given element up to the very top node of the HTML document. However, it can be very useful when used with a tag as demonstrated below. |
Or we could locate the table that has such a cell:
//td[text()="Siblings"]/ancestor::table
Decsendants
We can locate the descendants using the descendant
keyword:
//<knownXPath>/descendant::*
//<knownXPath>/descendant::tag
For instance, if we want to locate all elements in this page header, this would be the locator for it:
//header/descendant::*
Or we can locate all images inside the header:
//header/descendant::img
Locating n-th element with XPath
Sometimes we need to locate the n-th element with certain attributes. In order to do that we can use the [n]
notation. The general syntax for that will be:
//<elementXPath>[n]
For instance, we want to locate the third row in the table that contains the word "Relationship" in the header. Then the XPath would be:
//td[text()="Relationship"]/ancestor::table//tr[3]
You can use brackets to define which element will be counted. For instance, this selector will locate the third row in any table that has at least 2 rows:
//table//tr[2]
On the other hand, this selector will locate the rows in the second table:
(//table//tr)[2]
CSS selectors
There are various ways of locating an element using CSS selectors:
- by a tag and/or attribute value
- by class
- by id
- by other attributes
- by relation with another element
- locating n-th element
CSS selectors by the tag and/or attribute value
In CSS selectors there is no wildcard character. However, it provides the ability to locate elements without the tag name as well. Additionally, with CSS selectors there is a special way of locating elements by class and by id.
CSS selectors by class
In order to locate an element by class, you can use the dot notation:
.class-name
tag.class-name
For instance, you can locate the info panels in this article using these locators:
.info-panel
table.info-panel
CSS selectors by id
In order to locate an element by id, you can use the hashtag notation:
#id
tag#id
For instance, the first info panel on this page has an id "general-info". Thus, we would use of of these selectors to locate it:
#general-info
table#general-info
CSS selectors by other attributes
You can locate elements by the tag and/or other attributes. The general syntax looks like this:
tag
tag[attribute="attribute-value"]
[attribute="attribute-value"]
If you want to use the class and/or id along with other attributes, you can do it one of the following ways:
tag.class-name[attribute="attribute-value"]
.class-name[attribute="attribute-value"]
tag#id[attribute="attribute-value"]
#id[attribute="attribute-value"]
tag.class-name#id[attribute="attribute-value"]
.class-name#id[attribute="attribute-value"]
Following this syntax, the possible ways to locate the search box on top of this page, would be:
form[role="search"]
form.search[role="search"]
.search[role="search"]
Relative CSS selectors
Using CSS we can only locate child, descendant and sibling elements. Locating any ancestor element is not possible with CSS. Below you can find the main examples of how to create relative CSS selectors.
Locating child elements using CSS
The general syntax for locating a child element with CSS is:
parent-tag > child-tag
For instance, if we want to locate code block in a table cell, we would use this selector:
td > code
Locating descendant elements using CSS
The general syntax for locating a child element with CSS is:
ancestor-tag descendant-tag
Similarly to the previous example, let's locate a code block, but this time inside a table:
table code
Locating sibling elements with CSS
Siblings can be located through a parent or ancestor element. You can locate first, last or nth sibling.
To locate the first sibling, you can use this syntax:
parent-css > child-tag:first-child
ancestor-css descendant-tag:first-child
Similarly, if you want to locate the last sibling:
parent-css > child-tag:last-child
ancestor-css descendant-tag:last-child
If you would like to locate nth sibling, this is the syntax:
parent-css > child-tag:nth-child(n)
ancestor-css > descendant-tag:nth-child(n)
For instance, if we wanted to locate the first, the last and the third article in the list in the sidebar of this page, these would be the options for the CSS selector:
.collapsible-sidebar-body li:first-child
.collapsible-sidebar-body li:last-child
.collapsible-sidebar-body li:nth-child(3)
Locating n-th Element with CSS
If we want to locate the n-th element, this is the syntax for it:
element-css:nth-of-type(n)
For instance, if we wanted to locate the third header of the second level, this would be the selector:
h2:nth-of-type(3)
Comments
0 comments
Please sign in to leave a comment.