Wednesday, August 15, 2012

CSS Locator / CSS Selector Tutorial

CSS locating strategy is the fastest way to identify an element compared to any other locating strategy currently available. Many of the automation frameworks now uses CSS as a locating strategy for locating elements. In this blog I will explain about how to identify an element using CSS locators.

1. Locate an element using id.
<input id="textid" value="textid" type="text"/>    
<button id="buttonid">Button wiht id</button>

Consider the above html code of a text box and a button, you can locate the above elements in html using there "id" attribute value.
In CSS  an element with id is identified by appending "#" to the start of its id attribute value. For ex the above text element can be located as "#textid". Similarly the button element can be identified as "#buttonid"


2. Locate an element using class attribute.
<input class="textusingcls" value="Text with single class" type="text"/>    
<button class="btnusingcls">Button with single Class</button>

Consider the above html code of a text box and a button, you can locate the above elements in html using there "class" attribute value.
In CSS  an element with class is identified by appending "." to the start of its class attribute value. For ex the above text element can be located as ".textusingcls". Similarly the button element can be identified as ".btnusingcls"

Locating an element having more than one class, for ex. consider the following html code.
<input class="textcls1 textcls2" value="Text with multiple class" type="text"/>    
<button class="buttoncls1 buttoncls2">Button with multiple Class</button>
The above element can be identified by replacing the spaces between the class values with "." . The above elements can be located as ".textcls1.textcls2" and ".buttoncls1.buttoncls2" respectively.

3. Locate an element using html tag.
<input id="textid" value="textid" type="text"/>    
<button id="buttonid">Button wiht id</button>

Consider the above html code of a text box and a button. To locate the above elements using there html tags in css, you just have to use the tag name. For ex. The above two elements can be located as "input" and "button" respectively.

4. Locate an element using html tag, class, id all together.
<input id="textidcls" class="textidcls" value="Text with id and class" type="text"/>    
<button id="buttonidcls" class="buttonidcls">Button with id and Class</button>

Consider the above html code of a text box and a button. You can locate the above element using a combination of html tag, id and class all together. To do that just append all the three independent locator together. For the above element the unique locators will be "input#textidcls.textidcls" and "button#buttonidcls.buttonidcls" respectively.

5. Locate element based on Parent element:
<input class="textcls" value="Text" type="text"/>  
<button class="buttoncls">Button</button>
<div id="parent">
    <div id="project-label">4. Locate Child element:</div>
    <input class="textcls" value="Text" type="text"/>    
    <button class="buttoncls">Button</button>
    <div>
        <input class="textcls" value="Text" type="text"/>    
        <button class="buttoncls">Button</button>
    </div>
</div>

Consider the above html code, if you try to find the text element using css locator ".textcls" you will get 3 elements in return. In case you need to find the text box under the div element with id "parent" you can locate it using the locator "#parent .textcls", but this also gives you 2 text box elements that are under the element with id "parent".
To find the direct child element of the "#parent" element you can use the ">" sign of css locator. So if you use the locator "#parent > .textcls" it will give you the direct child of "parent" element.
In css if you use space between the parent and child element, it will return all the child elements under the said parent irrespective of the hierarchy.

6. Identify an element using attribute value:
<input test="excttxt" value="Text for exact attr. value" type="text"/> </br>
<input test="strttxt1234" value="Text for starts with option" type="text"/> </br>
<input test="1234endtxt" value="Text for ends with option" type="text"/> </br>
<input test="12cntntxt34" value="Text for contains option" type="text"/> </br>

Consider the above html code, there are 4 text boxes each having a different value for attribute "test".Each element can be uniquely identified by using the following strategies:
  • By exact attribute value: 'input[test="excttxt"] '
  • By using starts with: 'input[test^="strttxt"]'
  • By using ends with: 'input[test$="endtxt"]'
  • By using contains: 'input[test*="cntntxt"]'

I had created a dummy html page which can be download from the following link: CSS-Locator-demo
To use the demo for identifying a locator:
1. Unzip the downloaded zip and open the page "css_locator.html" in chrome or firefox.
2. Now go to console in the browser. For Chrome: Right Click -> Inspect Element -> Console. For Firefox: Right Click ->Inspect with Firebug -> Console.
3. Use the jquery way of identifying element in the cosole. To do that type $('<Ur CSS locator>') under console and press enter.
Jquery will find the matching element for the said css locator and display it on the console as a link. If you hover on the said link it will highlight the said element.

More info on CSS selector at W3C link

9 comments :

HarisH said...

HI i need the seleium handling for captcha

is there any possibilty of handling it instead of writing it manually by sleeping the thread
if possible notify me to harish.vanama24@gmail.com

Thank You

Varun Menon said...

Captcha feature is meant to make sure that it is not a automation script and a human is interacting on the page. There is no way to automate a captcha and if there is ,then it will become a big security threat.
Anyways to automate the captcha, you can talk to the developers to set a bit which gives you the same catcha again and again. Or take any value provided on the captcha field. This bit you can disable when you are releasing it to production.

Venkatesh Ainalli said...

Hi sir first of all billions thanks to you for this awesome work ..i'm just out of collage and joined company recently. i was asked to automate product.but i had difficulty in working with CSS selectors your tutorial is just awesome...

i have no words to tell how happy i'm...once again billions thanks to you sir

Varun Menon said...

Thanks for your feedback and support.

kdp said...
This comment has been removed by a blog administrator.
Karthik said...

Hi Varun,
I am running different tests opening a browser page (@Before) every time for each test (@Test). Is there any solution to open browser only once and perform all the tests. See my sample code below:

public class ArchiveTestData {

private static WebDriver driver = null;

@Before public void setUpManageUsersPage(){

try{
System.setProperty("webdriver.chrome.driver", "C://selenium//chromedriver.exe");
driver = new ChromeDriver();
driver.get("http://localhost:/");
driver.switchTo().frame("content");
driver.findElement(By.xpath("//input[@name='j_username']")).sendKeys("username");
driver.findElement(By.xpath("//input[@name='j_password']")).sendKeys("password");
driver.findElement(By.xpath("//input[@value='Login']")).click();
driver.switchTo().frame("menu");
driver.findElement(By.xpath("//html/body/table/tbody/tr[3]/td/table/tbody/tr[2]/td[2]/a")).click();
}catch(Exception e){
System.out.println(e);
}
}

@Test public void createfolderTest() throws InterruptedException{

try{
driver.switchTo().frame("content");
driver.findElement(By.xpath("//html/body/table/tbody")).click();
String page = driver.findElement(By.xpath("//html/body/table/tbody")).getText();
Assert.assertEquals("Admin Utility - Create Test Data Folder or Subfolder", page);

}catch(Exception e){
System.out.println(e);
//log.info(""+e);
}
}

@Test public void createInvalidfolderTest() throws InterruptedException{

try{
driver.switchTo().frame("content");
driver.findElement(By.xpath("html/body/table/tbody")).click();
String page = driver.findElement(By.xpath("html/body/table/tbody/tr[1]/td/h1")).getText();
System.out.println("Navigated to "+ page );
Assert.assertEquals("Admin Utility - Create Test Data Folder or Subfolder", page);
}catch(Exception e){
System.out.println(e);
}
}

@Test public void cancelfolderTest() throws InterruptedException{

try{
driver.switchTo().frame("content");
driver.findElement(By.xpath("html/body/table/tbody/tr/td/div[3]/a[2]")).click();
String page = driver.findElement(By.xpath("html/body/table/tbody/tr[1]/td/h1")).getText();
System.out.println("Navigated to "+ page );
Assert.assertEquals("Admin Utility - Create Test Data Folder or Subfolder", page);
String button = driver.findElement(By.xpath("//html/body/table/tbody/tr[1]/td/form/input[2]")).getText();
driver.findElement(By.xpath("//html/body/table/tbody/tr[1]/td/form/input[2]")).click();

}catch(Exception e){
System.out.println(e);
}
}

@After public void closeBrowsertest(){
driver.quit();
}

}


For every test, my browser page is opened present @Before and @ After. I tried putting inside @BeforeClass & @AfterClass but I am getting null pointer exception.

Thanks in advance for your help. Looking forward for your reply soon.

Varun Menon said...

You can define a BaseClass which will be extended by every of your Test classes. Then you can have a ThreadLocal implementation of a class which will provide you with the driver object.
You just call the respective class for your driver object. ThreadLocal will also make sure that you get a separate driver object for each thread.

Ralph Freshour said...

I was told by a developer that for my WebDriver script I need to write this css line for the code shown below:

[id$=governmentProperty] div.ui-state-active sppan.ui-button-text

ele = driver.findElement(By.cssSelector("input[id*='governmentProperty'] div.ui-state-active span.ui-button-text"));

But this does not work. Can you help me please?

ddiv id="A0588:search-panels:governmentProperty" class="ui-selectonebutton ui-buttonset ui-widget ui-corner-all boolean-value"
ddiv class="ui-button ui-widget ui-state-default ui-button-text-only ui-corner-left" id="aui_3_4_0_1_420"
input id="A0588:search-panels:governmentProperty:0" name="A0588:search-panels:governmentProperty" type="radio" value="Yes"
class="ui-helper-hidden" onchange="nc4prRequestLogisticsChanged();"
sppan class="ui-button-text ui-c" id="aui_3_4_0_1_419"Yes/sppan
/ddiv
ddiv class="ui-button ui-widget ui-state-default ui-button-text-only ui-corner-right ui-state-active"
input id="A0588:search-panels:governmentProperty:1" name="A0588:search-panels:governmentProperty" type="radio" value="No"
class="ui-helper-hidden" onchange="nc4prRequestLogisticsChanged();" checked="checked"
sppan class="ui-button-text ui-c"No/sppan
/ddiv
/ddiv

Varun Menon said...

@Ralph- Your html contains multiple elements which match the criteria "input[id*='governmentProperty']" of your locator. In this case the first element will be selected but the button that you are looking for does not exist under it hence you are getting an exception. You can use the nth: child option wit css in case you are sure that the index will always be maintained for the button.

Post a Comment