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

7 comments:

  1. 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

    ReplyDelete
    Replies
    1. 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.

      Delete
  2. 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

    ReplyDelete
    Replies
    1. Thanks for your feedback and support.

      Delete
  3. This comment has been removed by a blog administrator.

    ReplyDelete
  4. 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.

    ReplyDelete
    Replies
    1. 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.

      Delete