Functional Testing your Grails app with GEB



gr8conf.eu 

4/6/2014
Colin Harrington

$ whoami



Colin Harrington
@ColinHarrington
colin.harrington@objectpartners.com


Principal Consultant 

GEB






What is it?

Geb


(pronounced "jeb")



Geb


=

Webdriver 
+
Groovy 
+
JQuery like Content Selector
+
Page Object model

History

Started in 2009 by Luke Daley 

v0.1 in 2010

0.9.2 = current


Just like winter, 

1.0 is coming.





Uses




Testing!

Screen scraping

Automating

WebDriver


  • Selenium
  • Selenium RC
  • Selenium 2.0 aka WebDriver
  • Selenium Grid


Selenium RC   <   WebDriver

WebDriver



Code -> Driving -> Real Browser



{ Chrome, Firefox, Internet Exploder, 
Safari, PhantomJS, HtmlUnit, 
Android, iOS, Remote }

Example


// Create a new instance of the html unit driver
// Notice that the remainder of the code relies on the interface,
// not the implementation.
WebDriver driver = new HtmlUnitDriver();

// And now use this to visit Google
driver
.get("http://www.google.com");

// Find the text input element by its name
WebElement element = driver.findElement(By.name("q"));

// Enter something to search for
element
.sendKeys("Cheese!");

// Now submit the form. WebDriver will find the form for us from the element
element
.submit();

// Check the title of the page
System.out.println("Page title is: " + driver.getTitle());

driver
.quit();

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

Grails plugin




http://grails.org/plugin/geb



compile ":geb:0.9.2"

Testing with Grails  

BuildConfig.groovy
dependencies {
    test("org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion")
    test("org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion")
      
    // You usually only need one of these, but this project uses both
    test "org.gebish:geb-spock:$gebVersion"
    test "org.gebish:geb-junit4:$gebVersion"
}
GebConfig.groovy
driver = { new ChromeDriver() }

environments {
	
    // run as “grails -Dgeb.env=chrome test-app”
    // See: http://code.google.com/p/selenium/wiki/ChromeDriver
    chrome {
        driver = { new ChromeDriver() }
    }
	
    // run as “grails -Dgeb.env=firefox test-app”
    // See: http://code.google.com/p/selenium/wiki/FirefoxDriver
    firefox {
        driver = { new FirefoxDriver() }
    }
}
http://www.gebish.org/manual/current/all.html#grails

Basic Example




Content Selection

$(«css selector», «index or range», «attribute / text matchers»)

$("a", class: "brand") 

$("div.some-class p:first[title='something']") 

$("div.footer").find(".copyright") 

Interactions

click() 
Sending Keystokes:
$("input", name: firstName) << asdf
$("input", name: "firstName") << Keys.chord(Keys.CONTROL, "c") 

WebDriver API directly:
Actions, Drag and Drop, interact {...}
Control-click, etc.

interact {
    clickAndHold($('#element'))
    moveByOffset(400, -150)
    release()
} 

waiting

waitFor {} // use default configuration


// wait for up to 10 seconds, using the default retry interval
waitFor(10) {} 


// wait for up to 10 seconds, waiting half a second in between retries
waitFor(10, 0.5) {} 


// use the preset “quick” as the wait settings 
waitFor("quick") {} 
Browser.drive {
    $("input", value: "Make Request")
    waitFor { $("div#result").present }
    assert $("div#result").text() == "The Result"
} 

Javascript


Special 'js' object
  • read global scope
js."document.title" == "Book of Geb" 

js.gloallyVisibleJavascriptFunction(1,2)

  • js.exec()
  • Executes arbitrary Code

js.exec(1, 2, "return arguments[0] + arguments[1];") == 3 


jQuery Support

Built-in Support for jQuery


js.exec 'jQuery("div#a").mouseover();' 

is equivalent to: 

$("div#a").jquery.mouseover() 

...

  • Direct downloading

  • alert(), confirm() support

  • Multiple windows

  • Untrusted Certificate handling

  • Direct Driver interaction

Page Object Pattern

class GoogleHomePage extends Page {

    static url = "http://google.com/?complete=0"

    static at = { title == "Google" }

    static content = {
        searchField { $("input[name=q]") }
        searchButton(to: GoogleResultsPage) { $("input[value='Google Search']") }
    }
 
    void search(String searchTerm) {
        searchField.value searchTerm
        searchButton.click()
    }
} 

class GoogleResultsPage extends Page { ... }
Browser.drive {
    to GoogleHomePage
    search "Chuck Norris"

    at GoogleResultsPage
    resultLink(0).text().contains("Chuck")
} 

Content


class GoogleHomePage extends Page {
    static url = "http://google.com/?complete=0"
    static at = { title == "Google" }
   
    static content = {
        searchField { $("input[name=q]") }
        searchButton(to: GoogleResultsPage) {             $("input[value='Google Search']")         }
    }
 
    void search(String searchTerm) {
        searchField.value searchTerm
        searchButton.click()
    }
} 

Accessible via
page.searchField

Modules


Think Templates

Reusable modules that exist across multiple page hierarchies.
Header panel
class ExampleModule extends Module {
    static content = {
        button { $("input", type: "submit") }
    }
} 

class ExamplePage extends Page {
    static content = {
        theModule { module ExampleModule }
    }
}

Reporters


ScreenshotAndPageSourceReporter

Browser.drive {
    reportGroup "google"
    go "http://google.com"
    report "home page"
 
    reportGroup "wikipedia"
    go "http://wikipedia.org"
    report "home page"
} 

  • Reports dir
  • Listeners
  • cleanReportGroupDir()

Grails

/target/test-reports/geb/


${grails.project.test.reports.dir}/geb



Example

Remote WebDriver


  • Install and run the Remote WebDriver client/server
  • Opens a port
  • listens for commands



http://www.objectpartners.com/2012/04/24/start-building-out-automated-groovy-mobile-web-application-testing-on-your-iphone-or-ipad-with-geb-and-spock/

Sauce Labs



Browser Testing, 
Mobile web-app testing.


  • Video & screenshot support
  • Desktop & Mobile support
  • Behind the firewall tunnelling


Roll Your Own?





Good luck

Advanced Geb talk


Marcin Erdmann



Parallell Execution


Tomas Lin



Jenkins


Partitioning
XVFB = X Virtual Frame Buffer

Remote Control


Grails plugin:

compile ":remote-control:1.5" 



Sikuli


http://www.sikuli.org/

http://fbflex.wordpress.com/2012/10/27/geb-and-sikuli/

Others?

Questions?

Fin





Thank you

Functional Testing your Grails app with GEB

By Colin Harrington

Functional Testing your Grails app with GEB

  • 4,528