Selenium Tips - Intermediate CSS Selectors in Selenium

Posted by Matthew Heusser in SeleniumSelenium Resources

Following my previous Selenium testing Tip of The Week about Better locators in Selenium, this blog post will show you more CSS rules and how to create pseudo-classes. Not only can this help you move from XPATH to CSS, but it can help you overcome some testability issues.

NEXT SIBLING

Let’s start with navigating a list of elements. That is, you have one element you can reach, but you want to reach the next element in the list. For example, the next element might be the radio button to select an “order” that has just been created, with an ID of the order number. The server can process the order that was selected, but selecting the element might be tricky. The next sibling option ties to a specific element, then to the next element of a specific type, using the “+” operator.  Let’s take a look at an example:

//Literal HTML displayed as code begins  
<form><input class="username" type="text" />&lt;/input&gt;
<input class="alias" type="text" />&lt;/input&gt;</form>
//Literal HTML displayed as code ends

And what it looks like:

//Render this HTML as part of the web page begins
<form><input class="username" type="text" />&lt;/input&gt;
<input class="alias" type="text" />&lt;/input&gt;</form>
//Render this HTML as part of the web page ends

We’ve got two elements, one with a class of username, and one without a name. Say we expect the user interface to change, perhaps the class is generated by some code - but we know the next element of type input is the one we want to reach. So the next sibling of type input is the one we want  to hook to. Here’s the CSS selector for that:

css=form input.username + input

SELECTING BY HTML ATTRIBUTE VALUE

Let’s look beyond order, and instead tie to some other element, perhaps name. So, for example, let’s say the HTML attribute is “name” and the value we want to select is “username.” This form is legacy code that does not have a class, or perhaps the class is not unique. Here’s the sample HTML:

//Literal HTML displayed as code begins
<form><input name="username" type="text" />&lt;/input&gt; <input name="password" type="text" />&lt;/input&gt;
<input name="continue" type="button" />&lt;/input&gt; <input name="cancel" type="button" />&lt;/input&gt;</form>
//Literal HTML displayed as code ends

And what it looks like:

//Render this HTML as part of the web page begins
<form><input name="username" type="text" />&lt;/input&gt; <input
name="password" type="text" />&lt;/input&gt; <input name="continue" type="button" />&lt;/input&gt; <input name="cancel" type="button" />&lt;/input&gt;</form>
//Render this HTML as part of the web page ends

We can use CSS to grab an element by the value of the HTML attitude “name” - in this case the “name” of “username.” All with no ID and no need to create a class. Here’s the code:

css=form input[name='username']

Let’s say we want to get more specific. For example, if the form had to username fields, or if we are worried it might in the future. We can combine other attributes, such as type to chain filters to be more specific.

css=input[name='continue'][type='button']

In this example, Selenium will act on the input field with name of "continue" and type of "button"

CHOOSING A SPECIFIC MATCH

In  HTML, ul is the unordered list, and the li tag is for each list item. It is rare for these elements to have attributes like name, ID, or a different class. Yet the results can be pulled from a database, and the order they appear in might matter - so you want to grab the first sub-element of a ul, or the second, or the third, and look at the text contained inside.

The nth-child and nth-of-type selector in CSS allows us to do just that. Consider the following HTML:

//Literal HTML displayed as code begins
<ul id="recordlist"><p>Heading</p>
<li>Skateboard</li>
<li>Bicycle</li>
<li>Motorcycle</li>
<li>Car</li>
</ul>
//Literal HTML displayed as code ends

//Render this HTML as part of the web page begins
<ul id="recordlist"><p>Heading</p>
<li>Skateboard</li>
<li>Bicycle</li>
<li>Motorcycle</li>
<li>Car</li> </ul>
//Render this HTML as part of the web page ends

If we want to select the fourth li element (Motorcycle) in this list, we can use the nth-of-type, which will find the fourth li in the list.

css=ul#recordlist li:nth-of-type(4)

On the other hand, if we want to get the fourth element only if it is a li element, we can filter by nth-child which will select (Car) in this case.

css=ul#recordlist li:nth-child(4)

Note, if you don't specify a child type for nth-child it will allow you to select the fourth child without regard to type. This may be useful in other situations. Consider this raw HTML:

//Literal HTML displayed as code begins
<section id=”introduction”>
  <p>Paragraph 1</p>
  <p>Super Paragraph</p>    <!-- Want this one -->
</section>
//Literal HTML displayed as code ends

We expect the “p” element to change. The following code will match Super Paragraph:

css=ul#introduction *:nth-child(2)

SUB-STRING MATCHES

CSS in Selenium can do partial string matches for any attribute, such as id, name, clss, and so on. If you know what the attrribute starts with, use ^= to match the prefix. If you know how it send, use $= to match the suffice. *= will match if the text is anywhere inside of the attribute value. Here are some examples:

css=a[id^='id_prefix_']

This matches the first link (an “a” element) with an id that starts with the text "id_prefix_"

css=a[id$='_id_sufix']

This matches the first link with an id that ends with the text "_id_sufix"

css=a[id*='id_pattern']

And this matches if any of the id contains id_pattern.

MATCHING BY INNER TEXT

Finally for today we have match by inner text. That is, the text within the element contains certain text. In some cases, you can get two tests for one - if the  css matches, then the link exists on the page and has the text you are looking for. Here’s a simple example that matches a log out link.

css=a:contains('Log Out')

This will find a log out link that is anywhere on the page, which is much less brittle than an XPATH tied to the link by it’s specific location compared to other divs and form elements. It has the magical advantage of being simple, fast, and less brittle than some XPATH alternatives.

Next up in the series, we’ll take on finding the HTML which has focus, how to change focus between elements, and how to detect an object does not have focus.

//Insert tune in next week language with links, description of sauce labs here. Once it is up, turn “finding HTML elements by inner text in more detail” into a link to the article.

Discuss: Selenium Tips - Intermediate CSS Selectors in Selenium
0 Comments

Free Trial

Get access to a free 14-day trial version, or contact Sales for more information.