Selenium Tips - Intermediate CSS Selectors in Selenium

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.

Written by

Matthew Heusser

Topics

Selenium

Categories