In the previous part of this series, we kicked off talking about how to select web elements in protractor. We talked about the basic selectors and talked quickly about the css and xpath selectors.

In this part we will discuss both of css and xpath selectors much more deeply. How to write advanced css and xpath selectors. What about the performance of both of them comparably. And some tips and tricks in such advanced selectors. And much more. Let’s take off …

CSS Selectors Full Guide

Starting from the css selectors. We discussed four ways to select elements based on their css. Selecting based on css, className, cssContainingText, and deepCSS. But we didn’t talk much about the first one. And that what we will do now. We will give a comprehensive guide about how to write perfect css selectors. After this part, you will be able to create a css selector for any web element whatever its position in the DOM is deep or whatever it’s complicated.

Given this HTML block, all the possible ways to select element by css will be applied to

<ul class="upland">
  <ul class="product-team">
    <ul class="software-engineers">
      <li class="developer">Mohammed</li>
      <li class="tester" id="automation-tester">Moataz</li>
    </ul>
  </ul>
</ul>

Absolute Path: In the previous post, we used the . notation to get an exact match of an element in selection. Its in format .class.class.class.class. For example to select the developer, a css selector like .upland.product-team.software-engineers.developer is used. You can select the same element by chaining the tag name using > operator. So the same element can be selecting by ul>ul>ul>li.

Replacing the dot with a greater than sign makes it easier to isolate each node in the css selector. On contrary, it uses the tag name instead of the class name. And in most of the cases, the classes names are more descriptive than the tag names. But you still have the option to select with the tags concatinated together in case that the development team are using descriptive tag names.

Hybrid Path: After introducing the absolute bath, you may think that it will be perfect if it’s possible to mix both of the tag and the class name in one expression. Protractor (based on the webdriver) gives you the chance to do more than that. You can use all the tag, the class name, and the id in one expression. In this format tag .class #id is used to mix them up. So to select the tester with name Moataz, this is a perfect selector to do that ul .product-team.software-engineers #automation-tester. And of course you can use the class, tag, and id in any combination. It’s not mandatory to start your selector with the tag.

Attribute Value: Another way to use the combinations is to use the combination between the tag and one of the attributes with its value. It follows a schema like that tag[attribute='value']. It will be a selector like that to select Moataz tester li[id='automation-tester'].

You may see that step by step, the selectors become more readibly. And it’s the ultimate goal of this tutorial. Nothing better than writing readible and powerful selectors in the same time.

Attribute Containing Text: It’s still available to select by a sub-string inside one of the atrributes using this exression tag[attribute*='value']. Selecting Moataz tester will be done by this syntax li[id*='tester']. Yes, no more customization from the above selector than adding * after the attribute name.

Attribute Starting With Text:As well, it’s sometimes helpful to select all the elements that start with specific text. This time the customization comes by adding ^ operator to the general schema to become tag[attribute^='starting-with-text']. And to select the same element, you can use a selector like that li[id^='automation']

Attribute Ending with Text: The final customization to the same schema is to select and element based on the ending text. And this time we will add $ sign. So the schema becomes tag[attribute$='ending-with-text']. Again, to select the same element we use this selector li[id$='tester']

Id Inside Specific Tag: In some cases, you may have more than one element with the same id. May be a button which exists twice in a page for example. In such scenarios the frontend developer may give both of them the same id. And you will still be able to select both of them by id. And that’s in case of each of them is included in a different tag. And you can do that using this in this format tag#id. In our usual examplem, Moataz record can be selected by writing li#automation-tester.

Class Inside Specific Tag: As the above notation, you can do the same using the css class instead of the id. It’s doable by replacing the # by .. It means it will be tag.cssClass. Select the usual elemnt by typing li.tester.

Tag Name: Some web elements are used once per page in most case like the forms and tables. And it’s the simplest selector ever to select a unique element like that by just typing the tag name. Something like, form or table makes it perfect.

More Than a Seleector Separated by Commas: It may not be the selector which you will use everyday, but it’s still a very special that you are able to combine many CSS selectors in one expression. And it’s done by the , operator. So you can select both the developer and tester in the above HTML by writing li[id='automation-tester'],li[class='developer'].

xPath selectors full guide

In the previous post, we discussed the main idea behind the xPaths. We said that xPaths is a syntax for finding elements on a web page using XML path expression using HTML DOM structure. We took a look on the two different types of xPaths: the absolute path and the relative path. And we discussed how to convert an absolute xPath to a relative one to make it shorted and more readible.

In this post we will stop copying the xPath from the browser by right clicking on the web element in the inspector and select ‘Copy xPath’. Instead, we will start learn how to write more advanced relative paths. Those advanced ones are again shorter and more readible.

When you are able to write a relative xPath to any element in the DOM, you will be able to locate any element which doesn’t have something unique to be used for the location. But keep in mind as mentioned before, you shouldn’t go to xPath selectors as the first option. Two reasons behind that: the first is that it’s time consuming to write an effecient xPath selector. So taking in consideration that a simple web page has at least tens of web elements, one or two additional minutes to locate each element means hours of extra time for every page. The second reason is relating to the performance. And this point is going to be discussed in detail in the next session.

Now giving the same HTML snippet used in the css selectors section, let’s take a look on the possible ways to build xPath selectors:

<ul class="upland">
  <ul class="product-team">
    <ul class="software-engineers">
      <li class="developer">Mohammed</li>
      <li class="tester" id="automation-tester">Moataz</li>
    </ul>
  </ul>
</ul>

Attribute Value: The most direct way to write a relative xPath is to use the combinations between the tag and one of the attributes with its value. It follows a schema like that //tag[attribute='value']. It will be a selector like that to select Moataz tester //li[id='automation-tester'].

Attribute Containing Text: As for CSS selectors, you can select element by xPath based on the contained text of a specific atrribute using this exression //tag[contains(@attribute, 'value')]. Selecting Moataz tester will be done by this syntax //li[contains(@id, 'automation')].

Attribute Starting With Text: When it’s helpful to select all the elements that start with specific text. Web driver pupolates this notation to select elements by xPath based on the starting text //tag[starts-with(@attribute, ‘value‘)]. And to select the same element, you can use a selector like that //li[starts-with(@id, 'automation')]

Contained text: As we used to do with the cssContainingText() selector for css, we have the same option when it comes to xPath. To select an element based on the contained text, just use this expression //text[text()='value']. So selecting Moataz tester can be rewritten as //text[text()='Moataz']. Note that you need to type the exact match of the text value, substring won’t work for you!

That’s basically all what you need to know about the CSS and xPath selectors which are supported by Protractor (or more precisely, by webdriver). Let’s now compare between the performance of CSS selectors and the xPaths and then take a wider look on how to select between this jungle of available selectors.

How to choose between the selectors (Best practices):

  1. Basic selectors first: The first rule is simple. If you have one of the basic selectors (id, name, type, model, or binding) use it with no thinking.
  2. Concider CSS before thinking about xPath: If you don’t have start unique identifiers for your element, start playing with CSS selectors. If it’s impossible to do it in CSS, then try considering the xPath selectors. Therre are many reasons about it, but here is a summary of a long-run debate in the test automation comunity:
    1. Writing CSS selectors is faster. And when it come to complex elements and long expressions, the margin becomes larger for the sake of CSS.
    2. CSS selectors are more readible and easier to debug.
    3. CSS is faster in performance.
    4. Markup is very easily subject to change and therefore xpath locators require a lot of maintenance.
    5. CSS doesn’t allow can only traverse down the DOM (e.g. from parent to child) since xPath can both traverse down or walk up the DOM (e.g. from child to parent). You may think that it’s an advantage for the xPath. But when you take a sharper look it’s not always the case. Not being able to traverse the DOM up is more of an indicator that your page has poor design and could benefit from some helpful markup.
  3. Shorter is better: If you used to write high quality code, you propably know that it’s preferable for a single line of code not to pass 80 characters and they shouldn’t ever pass 120. So writing shorter selectors keeps this rule global to your project including the selectors since they used to be the longest line of code through the project.
  4. Readability: Most of case a shorter selector is more readible. However, some of longer selectors are more readible. So try to keep balance between the length and the readability of your selectors. A shorter and easily readible selector is the best ever.
  5. Avoid text locators for text that changees frequently: This means to avoid selectors such as by.linkText, by.buttonText, by.cssContainingText. For sure you don’t want your test to break once you change a small piece of text.

Outro

At this point, we were focusing more on the Page Object Model structure. We discussed the heart of a POM which is the selectors. We as well took a look on how to implement actions on them (you can review it in this section). Our journey inside this part is not done yet, but in the next few parts of this tutorial we are more focused on the specs. How to run well organized specs, building asynchronous tests, and collecting the test results from them.

Thanks for reading, and stay tuned ;)