Tuesday, October 25, 2011

Selenium Grid with WebDriver

I had earlier covered in my blog on how to execute your RC cases in selenium grid. But with the commencement of Selenium-2/Webdriver, grid setup has been changed. In the following blog I will cover how to set-up your grid and the changes that will be required for easy execution of cases.


Following things are required:
1. Selenium 2.xx version server jar and Java library. The latest one can be downloaded from the link: Selenium-2
2. Java 1.6 and above
3. TestNg jar . You can download it from the link: TestNG
4. Eclipse with TestNG plugin installed(optional)
5. ChromeDriver. Can be downloaded from: ChromeDriver


The Test Code
Following is an example of test-class that have a test case to search google for "testing" and verifying after clicking it on a link.

import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverBackedSelenium;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;

import com.thoughtworks.selenium.Selenium;

import junit.framework.Assert;

public class Google {
 private Selenium selenium;
 @Parameters({"browser","port"})
 @BeforeClass
 public void beforeClass(String browser,String port){
  DesiredCapabilities capability= new DesiredCapabilities();
  capability.setBrowserName(browser);
  try {
   WebDriver driver= new RemoteWebDriver(new URL("http://localhost:".concat(port).concat("/wd/hub")), capability);
   selenium = new WebDriverBackedSelenium(driver, "http://www.google.com");
  } catch (MalformedURLException e) {
   
   e.printStackTrace();
  }
 }
 
 @Test
 public void search() {
  selenium.open("/");
  selenium.type("id=lst-ib", "testing");
  selenium.click("//input[@value='Google Search']");
  for (int second = 0;; second++) {
   if (second >= 60)
    Assert.fail("timeout");
   try {
    if (selenium
      .isElementPresent("link=Software testing - Wikipedia, the free encyclopedia"))
     break;
   } catch (Exception e) {
   }
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  selenium.click("link=Software testing - Wikipedia, the free encyclopedia");
  for (int second = 0;; second++) {
   if (second >= 60)
    Assert.fail("timeout");
   try {
    if (selenium.isTextPresent("Software testing"))
     break;
   } catch (Exception e) {
   }
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {

    e.printStackTrace();
   }
  }
 }
 @AfterClass
 public void afterClass(){
  selenium.stop();
 }
 
}
In the above class I am using the TestNG "Parameter" property to provide different data set to the "BeforeClass" method "beforeClass". The beforeClass method accepts two properties "browser" and a "port".
These values are used for initialization of driver and in-turn for initialization of selenium object. In the above code I am using the "WebDriverBackedSelenium" class for creation of the selenium object, so that its easy for guys who had worked on Selenium-1 to understand the code. If you want the code to be purely WebDriver, you can directly use the "driver" object for defining your test-cases.
The main part in this test case is how the driver object is being created:
DesiredCapabilities capability= new DesiredCapabilities();
capability.setBrowserName(browser);
WebDriver driver= new RemoteWebDriver(new URL("http://localhost:".concat(port).concat("/wd/hub")), capability);
The above code creates an object of DesiredCapability and then set the browser value to it. Now using this "capability" object I am creating the webdriver object using the "RemoteWebDriver" class. This tells the selenium on which browser the test-case needs to run and where the server is located. In this example I am assuming the server to be running locally. In case it is on different system the "localhost" needs to be re-placed with the ip of the said system.

TestNG configuration
For parallel execution you need to use the TestNG configuration. Following is an "testng.xml" file for the above said test class. The said configuration executes the test-cases across different browser.


<suite name="Selenium TestNG Suite" parallel="tests"
    thread-count="5">

    <test name="Selenium TestNG - 1">
        <parameter name="browser" value="firefox" />
        <parameter name="port" value="4444" />
        <classes>
            <class name="com.test.testng.Google" />
        </classes>
    </test>
    <test name="Selenium TestNG - 2">
        <parameter name="browser" value="chrome" />
        <parameter name="port" value="4444" />
        <classes>
            <class name="com.test.testng.Google" />
        </classes>
    </test>

</suite>


In the above configuration, I am configuring TestNG to run "tests" in parallel. Also there are two different tests inside a suite. For each test a different "browser" parameter value has been configured.

Selenium-Grid server
Now start your grid using the following commands. Run each command in a seperate terminal or command prompt by going to the directory containing your selenium-server-standalone-2.x.x.jar. In the following example I am using the 2.7.0 version of selenium.

For Hub:

java -jar selenium-server-standalone-2.7.0.jar -role hub


For a firefox based node:

java -jar selenium-server-standalone-2.7.0.jar -role webdriver -hub http://localhost:4444/grid/register -port 5556 -browser browserName=firefox


For google-chrome based node:

java -Dwebdriver.chrome.driver=/path/to/chromedriver -jar selenium-server-standalone-2.7.0.jar -role webdriver -hub http://localhost:4444/grid/register -port 5555 -browser browserName=chrome

Before running  the above command  you need to provide the chrome-driver path to the property "-Dwebdriver.chrome.driver".

Now run your testng.xml from eclipse by selecting it -> Right click -> Run as -> TestNG suite(this will work only if you have TestNG plugin installed in your eclipse.)
Or you can choose other ways to execute "testng.xml" like from command prompt, using ant or maven.
Once you run the above testng.xml. TestNG will execute the cases from the Google class on grid across different browsers firefox and google-chrome as configured.


You can do configurations for environment like OS (Linux,Windows), browser, browser-version and all and then you can run you cases on particular type of environment by configuring them accordingly. More details can be found at the following URL:
http://code.google.com/p/selenium/wiki/Grid2

49 comments:

  1. Hi,
    I am using Webdriver for testing.
    In our application there is report, in which
    Xpath is same for column. See the below example:
    All combo boxes have same Xpath.
    All text boxes have same Xpath.
    All links have same Xpath.
    Then how to handle it.
    I want to write the code for selection of the combo box values and relative text for every row.



    |Column Name 1 |Column Name 2|Column Name 3|
    |Combo box | Text box |Link |
    |Combo box | Text box |Link |
    |Combo box | Text box |Link |
    |Combo box | Text box |Link |
    |Combo box | Text box |Link |

    Add another (This is the link to add new row) >>

    ReplyDelete
    Replies
    1. You can use the findElements method of webdriver to get the list of the matching elements. Then using this list you can iterate.

      Delete
  2. "Parameter 'browser' is required by @Configuration on method initializeDriver but has not been marked @Optional or defined,,,"what does this error means

    ReplyDelete
    Replies
    1. It means that you are using a variable/parameter "browser" in your method initializeDriver but forgot to pass the value to it using testng.xml or using @optional configuration of testng.

      Delete
  3. Hi Varun,

    I passed the value of browser in testng.xml, but still getting the same error.

    can u pls help. thanks in advance.

    ReplyDelete
  4. Hi Varun,

    I read your blog post and found it highly informative, but I have a related problem what if I want to find all the available nodes that are available for me to run the tests, I want to write a java code that extracts this information for me to find the nodes in the grid that are free and along with that find their configurations.

    I hope you can help me out with this. Thanks, in advance

    Ankit Sablok

    ReplyDelete
    Replies
    1. All these things are taken care by grid itself.. But still if you have to do these things, you may need to take a look at the source code of selenium grid...

      Delete
  5. Hi varun,
    By following above steps i am able to implement selenium grid successfully in my local machine.
    But i am getting some node registration error when i am trying to implement selenium grid in my team mate system from my local system.

    My team mate ip : 192.168.0.119

    For Hub: i am running

    java -jar selenium-server-standalone-2.25.0.jar -role hub

    For a firefox based node: i am running

    java -jar selenium-server-standalone-2.25.0.jar -role webdriver -hub http://192.168.0.119:4444/grid/register -port 5556 -browser browserName=firefox

    i am getting following error:

    16:46:40.609 INFO - using the json request : {"class":"org.openqa.grid.common.RegistrationRequest","capabilities":[{"platform":"VISTA","browserName":"firefox"}]
    ,"configuration":{"port":5556,"host":"192.168.0.128","hubHost":"192.168.0.119","registerCycle":5000,"hub":"http://192.168.0.119:4444/grid/register","url":"http:
    //192.168.0.128:5556","remoteHost":"http://192.168.0.128:5556","register":true,"proxy":"org.openqa.grid.selenium.proxy.DefaultRemoteProxy","maxSession":5,"brows
    er":"browserName=firefox","role":"webdriver","hubPort":4444}}
    16:46:40.610 INFO - starting auto register thread. Will try to register every 5000 ms.
    16:46:40.611 INFO - Registering the node to hub :http://192.168.0.119:4444/grid/register
    16:47:01.622 INFO - couldn't register this node : Error sending the registration request.
    16:47:27.626 INFO - couldn't register this node : hub down or not responding.

    ReplyDelete
    Replies
    1. Hi Varun,

      Please can u address the above issue.
      I am facing the same issue

      Delete
  6. Hi,
    I am trying to execute my framework(keyword driven) which is working fine with Firefox but not working with IE and Chrome.
    I found that if i give url inside test instead of @BeforeClass then only it is working.
    But it will not work for framework
    Can anyone help me on this.

    ---

    ReplyDelete
    Replies
    1. There may be some problem with the way the driver object is being initialized and used in your framework, just take a look at it once.

      Delete
  7. Hi! Varun where do i will find TestNG.xml file.Please help me.M new to selenium.Thanks in advance.

    ReplyDelete
    Replies
    1. You need to create your own testng.xml file for your test project, depending upon your project requirement.

      Delete
  8. Hi Varun

    How to run script in Internet explorer with latest selenium file.

    Please help.

    Regards,
    Keshav

    ReplyDelete
    Replies
    1. In the blog I had used chromedriver in the similar fashion you need to set path of Iedriver and then use it for your execution.
      Following link describes about IEdriver

      https://code.google.com/p/selenium/wiki/InternetExplorerDriver

      Delete
  9. Hi Varun,

    Im getting the below Error,

    java.lang.RuntimeException:
    http-equiv="Content-Type" content="text/html;charset=ISO-8859-1
    Error 500 org.openqa.grid.common.exception.GridException: Cannot extract a capabilities from the request [{"javascriptEnabled":false,"browserName":"firefox","class":"org.openqa.selenium.remote.DesiredCapabilities"}]


    HTTP ERROR: 500
    Problem accessing /wd/hub/session. Reason:
    org.openqa.grid.common.exception.GridException: Cannot extract a capabilities from the request [{"javascriptEnabled":false,"browserName":"firefox","class":"org.openqa.selenium.remote.DesiredCapabilities"}]





    at org.openqa.selenium.remote.RemoteWebDriver.throwIfResponseFailed(RemoteWebDriver.java:439)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:401)
    at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:74)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:61)
    at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:69)
    at com.selenium.gird.Google.beforeClass(Google.java:30)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:80)
    at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:564)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
    at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:138)
    at org.testng.internal.TestMethodWorker.invokeBeforeClassMethods(TestMethodWorker.java:175)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:107)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.access$0(SuiteRunner.java:333)
    at org.testng.SuiteRunner$SuiteWorker.run(SuiteRunner.java:368)
    at org.testng.internal.thread.ThreadUtil$2.call(ThreadUtil.java:64)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

    ReplyDelete
    Replies
    1. Have you registered a webdriver role with firefox browser to the grid?

      Delete
  10. Hi Varun,

    I want to use driver object itself so i am using
    @Parameters({"browser","port"})
    @BeforeClass
    public void setUp(String browser, String port){
    DesiredCapabilities capability = new DesiredCapabilities();
    capability.setBrowserName(browser);
    try{
    WebDriver driver = new RemoteWebDriver(new URL("http://10.100.15.24/wd/hub"), capability);
    } catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    }

    But in search Test , when i am trying to use driver object its giving error.

    Please help me

    ReplyDelete
    Replies
    1. What is the error? One more thing , I suppose you are not using the port parameter.

      Delete
    2. Hi Varun,
      Thanks for your reply. I am using this code
      @Parameters({"browser","port"})
      @BeforeClass
      public void setUp(@Optional("chrome")String browser, @Optional("4444")String port){

      DesiredCapabilities capability = new DesiredCapabilities();
      capability.setBrowserName(browser);
      try{
      WebDriver driver = new RemoteWebDriver(new URL("http://10.100.15.24:4444/wd/hub"), capability);
      } catch (MalformedURLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }

      }

      ad when i am trying to use this driver object in the search test , it doesn't give the desired function as if driver object is not created in the above line.


      Never used sign comes up nest to the this line
      WebDriver driver = new RemoteWebDriver(new URL("http://10.100.15.24/wd/hub"), capability);

      Plese help. Thanks

      Delete
    3. Problem is with you webdriver object.
      Declare it at class level and then initialize it in setUp.

      Delete
    4. yeah, that i know. i have declared it at class level and initialise it in setUp but its giving error in serach test (asking to add cast to driver). Can you please tell me what i am doing wrong.

      private WebDriver driver;
      @Parameters({"browser","port"})
      @BeforeTest
      public void setUp(@Optional("chrome") String browser,@Optional("4444") String port){
      DesiredCapabilities capability = new DesiredCapabilities();
      capability.setBrowserName(browser);
      try{
      driver = new RemoteWebDriver(new URL("http://10.100.15.24:4444/wd/hub"), capability);
      //selenium = new WebDriverBackedSelenium(driver, "http://www.google.com");
      } catch (MalformedURLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }


      }

      @Test
      public void search(){
      driver).open("http://google.co.uk");

      }

      Delete
    5. Could you please tell me what is the error tht u are facing.
      Also I see the following error in your code.

      driver).open("http://google.co.uk");

      Delete
    6. Please ignore that error ..it was just typo error. so if am using the above code its gives me error on the below line

      driver.open("http://google.co.uk");
      and when you hover over that error, it says
      The method open(String) is undefined for the type WebDriver

      and gives this solution at clicking on it

      ((DefaultSelenium) driver).open("http://google.co.uk");

      please tell me what am i doing wrong

      Delete
  11. Hi Varun,

    Awesome tutorial.It is working fine in Firefox and Chrome.
    Please help me out how to work in Internet Explorer via jar file through command prompt.
    Thanks in advance

    ReplyDelete
    Replies
    1. For ie try setting the property value "webdriver.ie.driver" with the IEDriver.exe similar to the chrome driver configuration

      Delete
  12. hi Varun,

    You havn't replied me, I am waiting for your answer from April 17

    ReplyDelete
  13. This comment has been removed by a blog administrator.

    ReplyDelete
  14. This comment has been removed by a blog administrator.

    ReplyDelete
  15. Hi Varun,

    I am Executing Below code TestNG Using Selenium Grid2

    @BeforeClass
    public void beforeClass() throws MalformedURLException {
    System.out.println("Before Test Exe");
    DesiredCapabilities cap=new DesiredCapabilities().firefox();
    /*cap.setBrowserName("firefox");
    cap.setPlatform(Platform.WINDOWS);
    cap.setVersion("7");*/
    System.out.println("After Desired Capabilities");
    driver=new RemoteWebDriver(new URL("http://localhost:4444/wd/hub"),cap);
    System.out.println("After Remote Webdriver");
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    But i am getting below Error
    FAILED CONFIGURATION: @BeforeClass beforeClass
    org.openqa.selenium.WebDriverException: Error forwarding the new session Empty pool of VM for setup {platform=ANY, browserName=firefox, version=}
    Command duration or timeout: 214 milliseconds

    ReplyDelete
    Replies
    1. Can you check your grid and see what properties our node shows in it.
      This issue may occur when the registered nodes dont match with the driver configuration you requested for execution..

      Delete
  16. Hi Varun,

    Can you please explain this in elaborate for android browsers. It would be of a great help

    ReplyDelete
    Replies
    1. I had worked on simple android driver on a mobile. But haven't integrated it with selenium grid.

      Delete
  17. Hi Varun

    I have some selenium grid related doubts:
    Currently we are trying to use GRID with JUNIT and able confgure and run the tests.
    My doubts are
    1. I observed that my testcases, when one testcase is running my other node is Idle and vice versa.
    IS THAT HOW testcases run in selenium grid

    2. Our main constraint is to run group of testcases in each node such that we can get the results in quick time. Can to tell how can I achieve that




    ReplyDelete
    Replies
    1. By default Junit execute the tests in a single thread and that may the reason that you see your tests getting executed on a single node rather than on multiple nodes.
      Configure your build tool or Junit to run your tests multi-threaded you will see different nodes being used for execution depending upon the threads you are using.

      Delete
    2. Hi Varun, Thanks for quick response..
      I have not described correctly

      For Example : I have 2 test suites TS1 and TS2.

      Each test suite has 2 Testcases. TS1 --> TC1, TC2 and other suite TS2 --> TC3, TC4

      Below mentioned code I am using in my build.xml file
      target name="allTests" depends="se_cmpl"
      property name="inTestMode" value="true"
      parallel threadCount="2"
      antcall target="sel_tests"
      param name="unitTestId" value="com/talentplus/test1/*.class" /
      /antcall
      antcall target="sel_tests"
      param name="unitTestId" value="com/talentplus/test2/*.class" /
      /antcall
      /parallel

      junitreport todir="${target.dir}/seleniumTestResults"
      fileset dir="${target.dir}/seleniumTestResults"
      include name="TEST-*.xml"
      /fileset
      report format="frames" todir="${target.dir}/seleniumTestResults/${DSTAMP}/report/html"
      /junitreport
      /target

      1. All testcases are running in all configured nodes (currently I am using node1, node2)
      Summarizing TC1,TC3 runs on node1 when running node2 will be Idle then TC1 and TC3 runs on node2 that time node1 will be Idle.

      But what I expecting is that each test case should run only on one node. Is that possible through selenium Grid.



      Delete
    3. You need to configure unique nodes in such case and use it for configuring your tests.

      Delete
    4. Please can you let me know how to configure tests with unique nodes.

      Delete
    5. Setup a node by using some constant params given in the Grid2 wiki of selenium. Then configure you driver object to point to a particular node by using the same configuration while creating driver.

      https://code.google.com/p/selenium/wiki/Grid2

      Delete
    6. Thank you very much for the reply..

      I will try out let you know about this

      Thanks
      -Bhanu

      Delete
    7. I have solved my problem, problem is that - multithread might work when we specify hardcoded/specific junit suites not by *.class(I am expecting to run all testcases). After fixing that Issue of running specific tests on nodes also worked.

      Thanks
      -Bhanu

      Delete
  18. I am seeing Testng related build file, please can you let me know what should with Junit
    {code}

    {code}

    ReplyDelete
  19. Sorry It didn't allow me last time with tags, so I tried with {code}. Below is the code

    suite name="Selenium Grid with webdriver" verbose="3" parallel="classes" thread-count="2"

    I am seeing Testng related build file, please can you let me know what should with Junit.

    ReplyDelete
  20. Hi Varun,

    How can i order hub to connect/execute TCs on only Specific node.

    ReplyDelete
  21. Hi Varun,

    I want to read the data from a PDF file and write to the excel using selenium webdriver . Can any one help me out.

    ReplyDelete
    Replies
    1. I never worked on reading something from pdf but hopefully there will be a utility for that available. Once you do you can use apache poi to write to excel file. And for your FYI there is nowhere selenium webdriver is going to be involved in this case its completely the coding that you need to do. Read from one file and write to another

      Delete
  22. Can i use selenium for testing in magento?

    ReplyDelete
  23. Hi Varun,

    I need to develop a Web Application which when clicked on a button should run multiple instances of selenium and run the test.

    I tried doing a servlet code for the same but the execution crashes at

    FirefoxDriver dr= new Firefoxdriver();

    Can i acheive this using Web Driver or grid. Could you please guide?

    ReplyDelete