How to configure WebDriver in Grails for your Geb Tests.

There has been a bit of discussion in the Grails mailing list about the lack of documentation on configuring webdriver for Geb.

In this post, I will outline the steps you will need to configure the following browsers:

  • Firefox
  • Chrome
  • Internet Explorer
  • Sauce Labs / Remote Webdriver
  • PhantomJS

HTMLUnit won’t be covered because it is broken for grails 2.2 and you shouldn’t be using HTMLUnit.

Adding Geb and Spock:

To start, open up your BuildConfig.groovy file.

Add the following dependency under the plugin block:

plugins{
      test ":geb:0.9.0-RC-1"
      test(":spock:0.7") {
            exclude "spock-grails-support"
      }
}

Add the following dependencies in your dependencies block:

dependencies {
       test "org.spockframework:spock-grails-support:0.7-groovy-2.0"
       test "org.seleniumhq.selenium:selenium-support:2.31.0"
       test "org.gebish:geb-spock:0.9.0-RC-1"
}

Versions of plugins may vary so check them on maven central before adding them.

Create a blank file called GebConfig.groovy in your test/functional/ directory. We will use this file to control which driver is called.

A Sample Geb Test:

Here is a sample geb test to check that your configurations are set up correctly. Add this to your test/functional folder. This test just goes to the grails.mx.org website and checks for the title. Call it LoginSpec.groovy

import geb.spock.GebReportingSpec
 
class LoginSpec extends GebReportingSpec {
    def "go to page"() {
        when:
        go "http://www.grails.org.mx"
 
        then:
        title == "GrailsMX | Groovy y Grails en tu idioma"
    }
}

Also, since this file is a GebReportingSpec (i.e, takes a snapshot of your test after executing and keeps a copy of the html file), you need to set a reporting directory in the GebConfig.groovy file. Add this to the top of your GebConfig:

reportsDir = "target/geb-reports"

You’re ready to test. After setting up each Geb config, simply call grails test-app functional: to see your tests run.

Firefox:

For firefox, you simply need to include the firefox driver. In your dependencies, add:

test "org.seleniumhq.selenium:selenium-firefox-driver:2.31.0"

At this point, you don’t need to add anything to your GebConfig file since it will run the first driver it finds. But if you want to set it explicitivly, add this to GebConfig.groovy:

import org.openqa.selenium.firefox.FirefoxDriver
driver = { new FirefoxDriver() }

Chrome:

For Chrome, you need to first download the chrome driver from https://code.google.com/p/chromedriver/downloads/list

After you have downloaded this file, you should save it locally. For example, /Users/tomaslin/drivers/ . Set an environment variable for webdriver.chrome.driver to this.

Alternatively, you can just do so in your GebConfig.groovy file.

Add the following to set up chromedriver:

import org.openqa.selenium.chrome.ChromeDriver
driver = {
   System.setProperty('webdriver.chrome.driver', '/Users/tomaslin/drivers/chromedriver')
   new ChromeDriver()
}

If you want to be able to switch drivers on the fly via configuration, follow this example – https://github.com/geb/geb-example-grails/blob/master/test/functional/GebConfig.groovy .

If you want to download the drivers automatically, follow this blog post – https://fbflex.wordpress.com/2013/01/06/geb-quickie-automatically-download-drivers-for-chrome-and-internet-explorer/

To get this to run, you need to add the chromedriver dependency in your BuildConfig.groovy file:

test "org.seleniumhq.selenium:selenium-chrome-driver:2.31.0"

Internet Explorer:

Internet explorer follows the same pattern as Chrome Driver above, except that the environment variable name is webdriver.ie.driver and it is downloaded from https://code.google.com/p/selenium/downloads/list . It is called something like IEDriverServer_x64_2.31.0.zip

Add the dependency to BuildConfig.groovy

   test "org.seleniumhq.selenium:selenium-ie-driver:2.31.0"

Then add the following code to your GebConfig file:

driver = {
   System.setProperty("webdriver.ie.driver", new File("C:/dev/Selenium/iexploredriver.exe").getAbsolutePath())
   new InternetExplorerDriver()
}

Selenium Grid / Sauce Labs / Remote Web Driver:

An exciting alternative for running Geb tests is to use Cloudified web servers or local instances available via selenium grid.

In order to use this, you need to add the remote driver dependency in BuildConfig.groovy

    test "org.seleniumhq.selenium:selenium-remote-driver:2.31.0"

If you are subscribed to Sauce Labs, you can simply use your credentials and demand a webdriver instance to be created on the cloud based on your requirements in your GebConfig.groovy file.

Here, I ask for a firefox instance on Windows 8.

import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.remote.RemoteWebDriver
driver = {
   DesiredCapabilities capabilities = DesiredCapabilities.firefox()
   capabilities.setCapability("version", "17")
   capabilities.setCapability("platform", "Windows 2012")
   new RemoteWebDriver(
     new URL("http://:<access_key>@ondemand.saucelabs.com:80/wd/hub"), capabilities
   )
}

To get a full list of sauce labs Operating systems and configurations, refer to their browsers page documentation. You can also specify a name for your test for easy identification.

My test finishes running and I see the result when I log onto the Sauce Labs website:

Screen Shot 2013-03-19 at 01.18.29

When I click on it, I get a detail recording of the test being ran, all the DOM elements and Events being fired, as well as a screenshot of the test:

Screen Shot 2013-03-19 at 01.19.12

This is pretty useful if you’re doing functional tests and continous delivery on the cloud in environments like CloudBees.

If you want to set up your own environments, for example to drive internet explorer on a virtual machine from your mac, you can use the Selenium Grid. The instructions for this are included in the link. You download a jar file to each machine, start a hub and start testing on each machine with the same instructions as above.

PhantomJS:

Finally, if you want to have a headless browsing experience that runs your tests really quickly, you can setup a Geb configuration that relies on PhantomJS. PhantomJS is a headless javascript browser based on Webkit. It is much better than HTMLUnit.

First, you need to install phantomjs via the instructions on their website. I just do this via homebrew ‘brew install phantomjs’.

After you have phantomjs installed, verify that it works by calling phantomjs in your terminal, type phantom.exit(); to exit the console.

You need to then add the ghostdriver jar to run phantomjs tests in Geb. Add the following dependency to your BuildConfig file:

    test( "com.github.detro.ghostdriver:phantomjsdriver:1.0.1" ) {
       transitive = false
    }

Note: The latest version of this driver is 1.0.3, but I had difficulties getting it to work properly on my MacOS installation. 1.0.1 works fine.

The PhantomJS driver is a little trickier, but it looks like this in GebConfig.groovy

import org.openqa.selenium.phantomjs.PhantomJSDriver
import org.openqa.selenium.remote.DesiredCapabilities
driver = {
    new PhantomJSDriver(new DesiredCapabilities())
}

You can also change some of the configurations. For our projects, for example, we wanted to fix the screen size to 1028×768 so that our mobile layout does not kick in. Our config then looks as follows:

import org.openqa.selenium.phantomjs.PhantomJSDriver
import org.openqa.selenium.remote.DesiredCapabilities
import org.openqa.selenium.Dimension
driver = {
    def d = new PhantomJSDriver(new DesiredCapabilities())
    d.manage().window().setSize(new Dimension(1028, 768))
    d
}

27 thoughts on “How to configure WebDriver in Grails for your Geb Tests.

  1. pledbrook (@pledbrook)

    Cool stuff. Useful for the functional testing chapter of Grails in Action 🙂

    One thing: in what way does HTMLUnit not work with Grails 2.2 and could you clarify why HTMLUnit shouldn’t be used anyway? I’d be interested to know the reasons.

    Reply
  2. John Braunhag

    Thank you very much! It’s extremely disheartening how much churn there is with Grails — management wants to use it “because it’s Java”, but we end up fighting a great deal to get something working (IE browser testing with Geb) that “just works” in other languages (i.e., Rails & Capybara).

    Reply
  3. Ronny Løvtangen

    Thanks for this useful post. I had disabled my geb tests after upgrading to Grails 2.2 due to problematic configuration, now that I removed HTMLUnit it works fine. I didn’t need the dependency “org.seleniumhq.selenium:selenium-support:2.31.0” though, what do I need that one for?
    There’s a small typo in the dependency for PhantomJS: “destro” should be “detro”.

    Reply
  4. Ronny Løvtangen

    The PhantomJS dependency pulls in selenium-java which pulls in selenium-htmlunit-driver and ultimately xerces:XerxecImpl:2.10.0 which causes problems.
    These are the direct dependencies of com.github.detro.ghostdriver:phantomjsdriver:jar:1.0.1:
    – org.seleniumhq.selenium:selenium-java:2.28.0
    – org.seleniumhq.selenium:selenium-server:2.28.0
    – org.seleniumhq.selenium:selenium-remote-driver:2.28.0

    These three dependencies pulls in lots of stuff, e.g. all the selenium drivers for android, iphone, chrome etc.

    It doesn’t look like any of those are needed to run my Geb tests with PhantomJS, so this works for me:
    test(“com.github.detro.ghostdriver:phantomjsdriver:1.0.1”) {
    transitive = false
    }
    Or at a minimum I need to exclude xerces:
    test(“com.github.detro.ghostdriver:phantomjsdriver:1.0.1”) {
    excludes ‘xercesImpl’
    }

    Reply
  5. Pingback: Questa settimana in Grails (2013-12) - luca-canducci.com - Il blog di Luca Canducci: notizie, tips e nuove tecnologie dal mondo dell’IT.

  6. Pingback: An Army of Solipsists » Blog Archive » This Week in Grails (2013-12)

  7. Raphael Oliveira

    I always get:
    java.lang.NoSuchMethodError: org.apache.http.conn.scheme.Scheme.(Ljava/lang/String;ILorg/apache/http/conn/scheme/SchemeSocketFactory;)V
    at org.openqa.selenium.remote.internal.HttpClientFactory.getClientConnectionManager(HttpClientFactory.java:59)
    at org.openqa.selenium.remote.internal.HttpClientFactory.(HttpClientFactory.java:48)
    at org.openqa.selenium.remote.HttpCommandExecutor.(HttpCommandExecutor.java:111)
    at org.openqa.selenium.chrome.ChromeCommandExecutor.(ChromeCommandExecutor.java:30)
    at org.openqa.selenium.chrome.ChromeDriver.(ChromeDriver.java:144)
    at org.openqa.selenium.chrome.ChromeDriver.(ChromeDriver.java:86)
    at geb.driver.NameBasedDriverFactory.getDriver(NameBasedDriverFactory.groovy:42)
    at geb.driver.CachingDriverFactory$_getDriver_closure3.doCall(CachingDriverFactory.groovy:80)
    at geb.driver.CachingDriverFactory$SimpleCache.get(CachingDriverFactory.groovy:30)
    at geb.driver.CachingDriverFactory.getDriver(CachingDriverFactory.groovy:79)
    at geb.Configuration.createDriver(Configuration.groovy:338)
    at geb.Configuration.getDriver(Configuration.groovy:327)
    at geb.Browser.getDriver(Browser.groovy:104)
    at geb.report.PageSourceReporter.getPageSource(PageSourceReporter.groovy:42)
    at geb.report.PageSourceReporter.writePageSource(PageSourceReporter.groovy:38)
    at geb.report.PageSourceReporter.writeReport(PageSourceReporter.groovy:29)
    at geb.report.CompositeReporter.writeReport(CompositeReporter.groovy:31)
    at geb.Browser.report(Browser.groovy:698)
    at geb.junit4.GebReportingTest.report(GebReportingTest.groovy:32)
    at geb.junit4.GebReportingTest.writeGebReport(GebReportingTest.groovy:51)

    My BuildConfig file is:
    dependencies {
    test “org.seleniumhq.selenium:selenium-chrome-driver:2.21.0”
    test “org.seleniumhq.selenium:selenium-support:2.21.0”
    test “org.gebish:geb-junit4:0.9.0”
    }

    plugins {
    test “:geb:0.9.0”
    }

    Grails 2.0.4 – Groovy 1.8

    Am I missing something?

    Reply
  8. Darren

    Hi,

    I am able to get the Geb Google search example working with IE/FF/Chrome/Phantomjs when using a connection with no proxy. However, when I run the same tests from the office, the proxy causes grief. FF and Chrome will prompt for username and password – which once entered allows the test to complete. IE and Phantomjs do not work when behind a proxy. Is there a way to set proxy host/port/username/password in the GebConfig file that will satisfy the office proxy? Googling hasn’t brought up anything that has worked so far.

    Thanks,
    Darren

    Reply
  9. Paul L (@lpaul7)

    Hi, nice article.

    Phantomjsdriver depends on selenium-remote-driver, so by setting transitive = false you should depend on it manually:
    test ‘org.seleniumhq.selenium:selenium-remote-driver:2.34.0’ // Needed by phantomjsdriver

    Reply
  10. Pingback: Groovy with Geb using Phantomjs and ssl certs | Agile, Grails, and other tech

  11. Pingback: Keep getting JavaScript messages in Geb test | BlogoSfera

  12. renu chudamani

    I already have Geb with maven (not Grails) and this was just the article I was looking for! I’ve just started looking at headless browser testing because I’ll soon be deploying these out to our internal Jenkins CI builds and needed to have a headless way to execute. Also, a somewhat cleaner way for the GebConfig implemenation that I have found useful is to use the environments switches. So my Geb Config looks like:

    environments {

    'ff' {
    driver = {
    def dr = new FirefoxDriver()
    dr.manage().window().maximize()
    return dr
    }

    }

    'chrome' {
    driver = {
    new ChromeDriver(DesiredCapabilities.chrome())
    }
    }
    'ie' {
    driver = {
    new InternetExplorerDriver()
    }
    }

    'phantomjs'{
    driver = {
    new PhantomJSDriver(new DesiredCapabilities())
    }
    }

    }

    Then by using the geb.env vm option you can have your configurations setup up for multiple browsers.

    Thank you for the useful post!

    Reply
  13. tonalf

    I am having problems trying to use Geb (0.9.2) and PhantomJS (1.9.7,) from a new Grails 2.3.7 app to scrape content from a web site (i.e., not from within a test). I run the following code:

    def t(String url) {
    def res = null
    Browser.drive {
    go url
    res = title
    }
    res
    }

    I get an UnableToLoadAnyDriversException listing htmlunit, Ffox, IE and Chrome drivers, but not PhantomJS. My dependencies are as follows:

    compile (“com.github.detro.ghostdriver:phantomjsdriver:1.1.0”) {
    transitive = false
    }
    compile “org.seleniumhq.selenium:selenium-remote-driver:2.40.0”
    compile “org.seleniumhq.selenium:selenium-support:2.40.0”

    Any idea of what I’m doing wrong?

    Reply

Leave a comment