When Front end developers need to locate elements on a web page, they use CSS selectors! Why not for selenium webdriver automation? image created via carbon.now.sh A wide variety of locators are being used in Selenium Web Driver automation. come last when you ask the question, “What are all the locators do you use frequently and why?” CSS selectors tops the list as one size fits all solution. There is also a tendency to use even when a proper is available. XPath XPath id Often, it is also lack of exposure to CSS selectors that drives them towards other options. People have mentioned that they are able to get the job done with other selectors. Fair enough, no harm was done. Why do you have to pay attention to CSS selectors? Answer this question. When you want to put a nail on the wall, will you use a brick, cobblestone or hammer? Brick and cobblestone can do the job. But, is the tool for the job. Hammer Just like that, there are ways to identify elements in an HTML document/DOM. But CSS selectors are the tool for the job. They have a specification that browsers need to follow If you are an automation engineer working on UI automation, invest time in learning CSS selectors (how about reading through the rest of the article?). You will reap benefits that are much more. I can hear your question: “But, it is so easy to copy the XPath. How about CSS selectors?” Trust me, in many browsers, the option is right there next to . You’ll find or . Copy XPath Copy CSS Selector Copy Selector Do you know why? Because the front-end developers use CSS selectors to apply visuals and behaviors of the web pages even before they come down to testing. Why CSS Selectors Were Invented? Have you ever wondered why all those classes and IDs are there? Did you ask anyone that I’d need some ID/classes included in these elements so that I can automate tests for this UI? If not you, then who asked for those attributes? The story goes back to the days when styles were added to HTML documents. This was before UI testing was automated. Each browser had its own way of styling documents. Document (HTML) authors were not in control as to how their documents were presented to readers. Authors needed a way to target tags and apply styles to arrive at the layout they wanted. proposed what would become the current cascading style language. Håkon Wium Lie Selectors to target specific elements was specified formally by . The browser developers take that specification as the requirement and build the browsers to support CSS. CSS Working Group Attributes such as and were added as hooks to target specific elements. They are there to help front-end developers style and attach behaviors to elements. on the same provisions, CSS selectors, to identify elements. id class Automation engineers can piggyback How CSS selectors are used? To style an element, Front end developers need to locate the element first and then apply styling rules. It looks like this: #logo{ color: white; background: black; } That CSS snippet says, apply and styles to any element with an ID of . Normally, ID will be unique in any HTML document carefully crafted. But there are chances for multiple developers working on the same page to use the same ID for different elements. Most of the time, without knowing it is already being used. Don’t worry, they’ll eventually catch up with that bug, but the point is the browser throws no warning. You should tell the developers when you find such scenarios. color background logo The JavaScript developer who wants to take the for a spin writes code like this: logo let element=document.querySelector("#logo"); rotate(element); Don’t worry about the implementation of , but just look at the first line. is a native API available to select elements in a browser. …and it takes CSS selector syntax. rotate document.querySelector In fact, you can use it within . JavascriptExecutor Since Front End Developers are using CSS selectors to locate elements (either to style them / amend the elements / to attach behavior to elements), it makes sense for the UI test automation engineers also to use the same API to locate elements. Convinced? Here is a preview of different selectors replaced by CSS selector. Other Selectors => By.cssSelector ------------------------ => -------------- By.className("register") => ".register" By.tagName("table") => "table" By.id("unique_id") => "#unique_id" By.name("login") => "[name=login]" By.xpath("//body/nav") => "body > nav" By.xpath("//body//nav") => "body nav" Four Selectors Let’s look at primitive selectors to start with. There are just about 4 you need to master and this is the easy part. Hash for IDs # Any element with a particular ID can be located using by prefixing a hash to the ID. By.cssSelector # For example: By.cssSelector("#logout") will help you locate an element that has ID with a value . It doesn’t matter what the tag name is. It could be a link or a button, but finds it. #logout logout cssSelector Usually, the ID is unique. It’s a fair assumption that there’s usually one. Assumptions can go wrong. Twenty developers working on a very busy UI might end up slipping the same ID on two different elements. So, if you wanted to pair it with a tag, you can do so. Put the tag name in front of the ID. By.cssSelector("a#logout") This selector is even more specific. It says, . find an anchor tag (a link) with an ID valued as _logout_ Dot for Classes . Now that we know how to deal with IDs, locating elements by class names will only be easier than ever. You need to prefix a dot to the class name to find an element with such a class. . Example overdue: By.cssSelector(".btn_red") That’s going to be a red button (if the developer adds relevant styles), but let’s not worry about that. This selector will identify an element with a class . If more than one element is found, the first one is returned. btn_red And if you wanted to combine a tag name and a class name? By.cssSelector("a.btn_red") That makes sense, doesn’t it? Tag stays the same Now, this one is even easier. What if you want to locate a particular element using its tag name? . Just the tag name will do. No prefix, no suffix That will give you the first table on the page. for Attributes [attr] The last selector among the four. This is entirely based on attributes within an element. HTML elements tend to have attributes such as , , , , , , and a lot more under prefix. id name class type src href alt data- All these attributes can be used to identify elements if you know that their attributes are uniquely identifiable. Here is an example: <img src="logo.png" class="top"> The locator could be any one of these: By.cssSelector("[src]") By.cssSelector("[src=logo.png]") By.cssSelector("img[src=logo.png]")By.cssSelector("img.top[src=logo.png]" The first one identifies all elements with a attribute src The second one locates by attribute with a specific value src Third one uses tag name, attribute and its value Fourth one uses tag name, class name, attribute & specific value They all differ in their specificity. The last one is very specific, the first one is very generic. It is also possible to specify conditions such as , or for attribute values. starts with ends with contains Few examples: The html first: <input type="text" class="form_text"><input type="email" class="form_email"> <input type="radio" class="form_radio"> And a few locators using attributes: By.cssSelector Description input elements with type attribute containing the text in the value input elements with type attribute starting with input elements with type attribute ending with "input[type*=form]" form "input[type^=form]" form "input[type$=radio]" radio Four Combinators We saw four different selectors that form the basis of CSS selectors family. We’ll now look at four combinators that give special powers to those CSS selectors. Plus for Adjacent Sibling + If you want to select an element that follows another element, you can use adjacent sibling combinator using a plus . + Let’s set up some sample HTML: <div id='profile'> <img src='head.png'> <h1>Mr.Neo</h1> <p>The one</p></div> If you wanted to select all tags that are placed right after an tag, you can use the following: h1 img By.cssSelector('img + h1') If you wanted to select all tags that follow a tag, this would help: p h1 It is the rightmost element that is selected. For example, while using , the element is selected. is there as a supporting actor. h1 + p p h1 Finally, what if you wanted to select tag from the previous HTML snippet? Food for thought. img Tilde for General Sibling ~ We saw what plus does. What if you wanted to check if an element is a sibling of another element, not necessarily an immediate sibling? + That’s where the general sibling combinator comes to rescue. It uses tilde sign to indicate a general sibling. ~ Let’s set up a HTML snippet showing your name and photos: <div> <h1> Your name!</h1> <img src='pic1.png'> <img src='pic2.png'> <img src='pic3.png'> </div> If you wanted to access all images that are a sibling of a tag, you can use the general sibling combinator. If there is only one , you’ll get just that. h1 img By.cssSelector('h1 ~ img') In this instance, it doesn’t matter if the tags follow immediately. What matters is, they all have the same parent and tags are a sibling to . img h1 img h1 What if you use ? You’ll get the last two. Go figure. img ~ img And by the way, your dear most gives you a way to get elements by sibling via special function: xpath By.xpath("//img/following-sibling::h1") Angle Bracket For Children > Siblings are fine. But children started crying now. Let’s pay attention to them. These are widely used combinators too. You can target an element which is a direct child of a parent element using RIGHT ANGULAR BRACKET sign. > We can reuse some of our earlier HTML snippets: <div id='profile'> <img src='head.png'> <h1>Mr.Neo</h1> <p>The one</p> <div id='crew'> <img src='crew1.png'> <h2>Mr. Morpheus</h2> <p>The other one</p> </div></div> All three elements can be located using the following options: By.cssSelector('#profile > img')By.cssSelector('#profile > h1')By.cssSelector('#profile > p') These selectors do not locate or tags within the section. Because they are not direct children of element. They are descendants, but not children. img p crew #profile Space for Descendants We are now down to the fourth and last combinator, the descendant combinator which is designated by a white space . Let’s use the same HTML: <div id='profile'> <img src='head.png'> <h1>Mr.Neo</h1> <p>The one</p> <div id='crew'> <img src='crew1.png'> <h2>Mr. Morpheus</h2> <p>The other one</p> </div> </div> Here is what happens: Locator Description targets two tags targets the only tag targets the only in there targets two tags #profile img img #profile h1 h1 #profile h2 h2 #profile p p You see the difference. Descendant combinator selects all matching tags as long as they are descendants of the parent element given. A small white space has so much meaning! Twenty Four Pseudo Classes There are about 24 pseudo-classes to help you. You can find them in . But, we’ll look at four to pique your interest. the specification :not This one is to negate all you’ve learned so far. What will do without negatives? Let’s say you want to target an element without a particular class/id/attribute. will come to your aid. :not The HTML: <input type="text" class="required" /><input type="text" class="required"/><input type="text"><input type="radio"><input type="email"> If you wanted to locate an input box that is not mandatory (which does not have a class so to speak): required By.cssSelector('input:not(.required)') If you wanted to select all inputs that are not type, then will do. email 'input:not([type=email])' And you can chain them too, like this: . That would give you all inputs that are not radio buttons and do not have a class . In this case, that’s just one type and another type inputs. input:not([type=radio]).not(.required) required text email :nth-child This one helps you with targeting a particular element based on its position. <div id='profile'> <h1>Name</h1> <img src='pic.png' /> <img src='background.png' /> <p>Summary...</p> <p>Details...</p> <p>Conclusion...</p> </div> Remember child selector from previous sections. We are going to use it. How do you say, “Get me the second child within the profile”. will do. denotes any tag and looks for a particular child based on the number you’ve given. #profile > *:nth-child(2) * nth-child You could have used the right tag name instead of , as in . You need to be careful when the tag name does not match. No element will be selected if you use a tag name that is not there. For example, returns nothing, as the second child is not a tag. * #profile > img:nth-child(2) #profile > h1:nth-child(2) h1 takes input like a number, , and . You can read like, every 3rd element starting from the 2nd element. MDN defines it as . This is used more in terms of styling elements. May not be so much for test automation. Let’s leave it right there. :nth-child odd even 3n+2 3n+2 An+B There is another one to get an element counting from bottom: . For example, will give you the last child, which is tag that has the text “Conclusion…”. The spec has as a pseudo-class that will give you the similar outcome. :nth-last-child #profile > *:nth-last-child(1) p :last-child I’ll leave you to guess what would return. :first-child :nth-of-type While takes all children into account, takes only the tag type into account. Let’s use the same piece of code. nth-child nth-of-type <div id='profile'> <h1>Name</h1> <img src='pic.png' /> <img src='background.png' /> <p>Summary...</p> <p>Details...</p> <p>Conclusion...</p></div> We’ve seen that, would return nothing, as first child is , but returns the first image. The spec also has something called as a shorter version. #profile > img:nth-child(1) h1 #profile > img:nth-of-type(1) :first-of-type What do you do to count from the bottom (reverse order)? Yeah, will come to your help. You also have to get the bottom-most child of the specified type. :nth-last-of-type :last-of-type :disabled One last pseudo-class we’ll look at is . This is handy when you look for a particular element that is either disabled or enabled. In fact, has classes like , and other pseudo-classes for you to use. :disabled the specification :enabled :checked In Xpath’s defense Knowing CSS selectors and then choosing XPath as a solution is different from NOT knowing CSS selectors and choosing XPath. Final words, do not get discouraged if you have been using all the while. By now, you would have seen that they are very similar in nature. They have their own pros and cons. perform well as they are natives to the browser. is more readable in certain instances. Whichever gets the job done is ok. One of these make your code readable? Go for that. Performs well over the other, choose that. Just don’t limit your options. XPath cssSelectors XPath In my experience, test automation engineers started using universally. So, this article was to add a counterweight to so that the scale is balanced against . In fact, John Resig, creator of jQuery has written about such a can be (years ago). XPath cssSelectors XPath comparison showing how powerful xPath References Try this diner game for practice. Official specification Level 3 Official draft Level 4 The ever friendly MDN reference All right! Did you find this useful? Use your claps to let me know. Thanks for your time. Originally published at www.pineboat.in . You should subscribe here , I’ll let you know when I write something new. Got you covered if you are going back to RSS feeds .