Ultimate Web Automation using WebDriver,
                    Groovy, JQuery and Domain Modelling
                                       It is just not all about Selenium 




Gaurav Bansal
Principal Consultant, Xebia

Phone: +91-989-984-9992
E-mail: gbansal@xebia.com
Challenges…
More Deliverables
  Fewer resources
  In less time
  With high quality
Finding Tool
Cost effective approaches
Integrated Framework
Web Automation Challenges..
Challenges                             Solution (Theory)

Multiple Browsers, Multiple Versions   Native to Web Browsers

                                       Powerful Element Querying
Complex Web Elements                   Capabilities


Coupling of Env. in scripts            Configuration Management

Duplicate/Unreadable/Non-
Maintainable Code                      Domain Modelling

Results - Required Statistics,
Screenshot etc                         Good Reporting


Boilerplate Code                       DSL


Test Representation Problem            BDD
Web Automation Solution..
Solution (Theory)           Solution (Practical)

Native to Web Browsers

Powerful Element Querying
Capabilities


Configuration Management               GEB
Domain Modelling            Geb’s Page Class
Good Reporting                     Geb
                             Geb’s Browser
DSL                               Class
BDD                                  Spock
What is Geb?
Geb is a browser automation solution.

It brings together the…
  Cross browser automation capabilities of
   WebDriver
  Elegance of jQuery content selection
  Expressiveness of the Groovy language
  Robustness of Page Object modelling
WebDriver
Successor to the Selenium project.
Also known as “Selenium 2”.
Sponsored and driven by Google.
Becoming a W3C standard.
  http://dvcs.w3.org/hg/webdriver/raw-
   file/515b648d58ff/webdriver-spec.html
Cross-browser Automation
What is cool new in WebDriver?
PhantomJS Based
 Ghost Driver.

Implementation
 of WebDriver Wire
 Protocol.

Run your tests without
 launching a browser.
GhostDriver 1.0.0
   Navigation
   Page content extraction
   Arbitrary JS execution
   Window handling
   Frame handling
   Screen-shot generation
   Cookies
   Element Search, Localization & Manipulation
   Mouse interaction (even
    though doubleClick and rightClick seems to be a bit
    flaky)
   Keyboard interaction
Demo…
WebDriver API
Geb sits on top of WebDriver.

Geb never talks to the actual browser
 because that's what WebDriver does.
Geb's inspiration
“Navigator API” that is inspired by jQuery.

  // This is Geb code, not jQuery JavaScript…
    $("h1").previous().children();


API is not identical.
Dynamic JVM Lang.
Groovy is…
  Compiled, never interpreted
  Dynamic, optionally typed
  99% Java syntax compatible
  Concise & clear
  Great for DSLs
  A comfortable Java alternative for most
Geb & Groovy
Geb uses Groovy's dynamism to
 remove boilerplate.
 import geb.*
 Browser.drive {
       to GoogleHomePage
       at GoogleHomePage
        search.field.value("wikipedia")
        waitFor { at GoogleResultsPage }
        assert firstResultLink.text() == "Wikipedia"
        firstResultLink.click()
        waitFor { at WikipediaPage }
      }
Page Objects
 The key to not pulling your hair
out when dealing with web tests.
What are they?
 In a phrase: Domain Modelling.

 By modelling and creating abstractions, we can isolate implementation
  detail.

    $("input[name=username]").value("user")
    $("input[name=pwd]").value("password")
    $("input[type=submit]").click()

 Is far more fragile than this…

    void login(String username, String password) {
           $("input[name=username]").value(username)
           $("input[name=pwd]").value(password)
           $("input[type=submit]").click()
    }

    login("user", "password")
Browser has-a Page
Browser.drive {
     to GoogleHomePage
     at GoogleHomePage
     search.field.value("wikipedia")
     at GoogleResultsPage
     assert firstResultLink.text() == "Wikipedia"
     firstResultLink.click()
     waitFor { at WikipediaPage }
     }


 The to() and click() methods are changing the
  underlying page.
 You can refer to the current page's content and
  methods just by name.
Geb's Page Objects
Geb builds the Page Object pattern
 directly into the framework (though it is
 optional).
  import geb.*

  class GoogleHomePage extends Page {
        static url = "http://google.com/ncr"
        static at = { title == "Google" }
        static content = {
           search { module GoogleSearchModule }
        }
  }
Geb's Page Objects
Features the “Content DSL” for naming
 content in a dynamic and powerful way.

  import geb.*
  class GoogleResultsPage extends Page {
  static at = { waitFor { title.endsWith("Google Search") } }
  static content = {
          search { module GoogleSearchModule }
         results { $("li.g") }
          result { i -> results[i] }
         resultLink { i -> result(i).find("a.l", 0) }
           firstResultLink { resultLink(0) } } }
Modules
Modules are repeating
 and/or reappearing content.
import geb.*
class GoogleSearchModule extends Module {
   static content = {
      field { $("input", name: "q") }
      button(to: GoogleResultsPage) { $("input", value: buttonValue) }
   }
Testing
Geb's testing adapters
Geb for Testing
 Geb can be used with…
   Spock
   JUnit (3 & 4)
   TestNG
   EasyB
   Cucumber (Cuke4Duke)

 The majority of Geb users use Spock.
 Geb can dump HTML and screenshots for each
  “test” to help in debugging.
Navigator API
jQuery inspired content
  selection/navigation
Attribute/Text match
Can match on attribute values:
   //<div foo="bar">
   $("div", foo: "bar")

 The “text” attribute is special:
   //<div>foo</div>

   $("div", text: "foo")

Can use Regular Expressions:
   //<div>foo</div>
   $("div", text: ~/f.+/)
Relative Content
 $() returns a Navigator that allows you to find
  relative content.
   $("p").previous()
   $("p").prevAll()
   $("p").next()
   $("p").nextAll()
   $("p").parent()
   $("p").siblings()
   $("div").children()

 Most of these methods take selectors, indexes
  and attribute text/matchers too.
  $("p").nextAll(".listing")
Content DSL
Content DSL
class GoogleResultsPage extends Page {
    static content = {
         results { $("li.g") }
         result { i -> results[i] }
         resultLink { i -> result(i).find("a.l", 0) }
         firstResultLink { resultLink(0) }
    }
}

Content definitions can build upon each
 other.
Content definitions are actually templates.
Optional Content
class OptionalPage extends Page {
     static content = {
     errorMsg(required: false) { $("p.errorMsg") }
   }
 }

By default, Geb will error if the content you
 select doesn't exist.
The “required” option disables this check.
Dynamic Content
class DynamicPage extends Page {
    static content = {
       errorMsg(wait: true) { $("p.errorMsg") }
 }
}

 Geb will wait for some time for this content to
  appear.
 By default, it will look for it every 100ms for 5s
  before giving up. This is highly configurable.
 Same semantics as the waitFor {} method that
  can be used anywhere.
Expensive Content
class ExpensivePage extends Page {
   static content = {
     results(cache: true) { $("li.results") }
     result { results[it] }
 }
}


 By default, all content is transient.
 The cache option instructs Geb to hold on to the
  content, avoiding redundant lookups.
 Use carefully, can cause problems with dynamic
  pages.
Navigation
Getting around
The to() method
class GoogleHomePage extends Page {
   static url = "http://google.com/ncr"
}


Pages can define a url that defines the
 page location.
The to() method sends the browser there
 and sets that as the current page object.
Content based navigation
class FrontPage {
   static content = {
   aboutUsLink(to: AboutUsPage) { $("div#nav ul li a", text: iStartsWith("About Us")) }
    }
}

When this content is clicked, the
 underlying page will be changed
 implicitly.
     to FrontPage
     aboutUsLink.click()
     page instanceof AboutUsPage
At Checking
The “at checking” mechanism enables fail
 fast and less debugging.
class LoginPage extends Page {
   static at = { $("h1").text() == "Please log in" }
 }

browser.at LoginPage

Will throw an exception if every statement
 of the at check is not true.
Driver Management
Geb caches the WebDriver instance (per
 thread) and shares it across test cases.
Manages clearing cookies and is
 configurable.
Config. Management
Looks GebConfig.groovy file on classpath.
  driver = {
  new FirefoxDriver()
  }

  waiting {
  timeout = 2
  slow { timeout = 100 }
  }

  reportsDir = "geb-reports“

  environments {
  chrome { driver = "chrome" }
  }
Demo….Spock Example
Summary




JUnit4       Spock   Grails
  TestNG   EasyB
Thanks




            @gaurav_bansal
            gbansal@xebia.com /

Agile NCR 2013 - Gaurav Bansal- web_automation

  • 1.
    Ultimate Web Automationusing WebDriver, Groovy, JQuery and Domain Modelling It is just not all about Selenium  Gaurav Bansal Principal Consultant, Xebia Phone: +91-989-984-9992 E-mail: gbansal@xebia.com
  • 2.
    Challenges… More Deliverables Fewer resources In less time With high quality Finding Tool Cost effective approaches Integrated Framework
  • 3.
    Web Automation Challenges.. Challenges Solution (Theory) Multiple Browsers, Multiple Versions Native to Web Browsers Powerful Element Querying Complex Web Elements Capabilities Coupling of Env. in scripts Configuration Management Duplicate/Unreadable/Non- Maintainable Code Domain Modelling Results - Required Statistics, Screenshot etc Good Reporting Boilerplate Code DSL Test Representation Problem BDD
  • 4.
    Web Automation Solution.. Solution(Theory) Solution (Practical) Native to Web Browsers Powerful Element Querying Capabilities Configuration Management GEB Domain Modelling Geb’s Page Class Good Reporting Geb Geb’s Browser DSL Class BDD Spock
  • 5.
    What is Geb? Gebis a browser automation solution. It brings together the… Cross browser automation capabilities of WebDriver Elegance of jQuery content selection Expressiveness of the Groovy language Robustness of Page Object modelling
  • 6.
    WebDriver Successor to theSelenium project. Also known as “Selenium 2”. Sponsored and driven by Google. Becoming a W3C standard. http://dvcs.w3.org/hg/webdriver/raw- file/515b648d58ff/webdriver-spec.html
  • 7.
  • 8.
    What is coolnew in WebDriver? PhantomJS Based Ghost Driver. Implementation of WebDriver Wire Protocol. Run your tests without launching a browser.
  • 9.
    GhostDriver 1.0.0  Navigation  Page content extraction  Arbitrary JS execution  Window handling  Frame handling  Screen-shot generation  Cookies  Element Search, Localization & Manipulation  Mouse interaction (even though doubleClick and rightClick seems to be a bit flaky)  Keyboard interaction
  • 10.
  • 11.
    WebDriver API Geb sitson top of WebDriver. Geb never talks to the actual browser because that's what WebDriver does.
  • 12.
    Geb's inspiration “Navigator API”that is inspired by jQuery. // This is Geb code, not jQuery JavaScript… $("h1").previous().children(); API is not identical.
  • 13.
    Dynamic JVM Lang. Groovyis… Compiled, never interpreted Dynamic, optionally typed 99% Java syntax compatible Concise & clear Great for DSLs A comfortable Java alternative for most
  • 14.
    Geb & Groovy Gebuses Groovy's dynamism to remove boilerplate. import geb.* Browser.drive { to GoogleHomePage at GoogleHomePage search.field.value("wikipedia") waitFor { at GoogleResultsPage } assert firstResultLink.text() == "Wikipedia" firstResultLink.click() waitFor { at WikipediaPage } }
  • 15.
    Page Objects Thekey to not pulling your hair out when dealing with web tests.
  • 16.
    What are they? In a phrase: Domain Modelling.  By modelling and creating abstractions, we can isolate implementation detail. $("input[name=username]").value("user") $("input[name=pwd]").value("password") $("input[type=submit]").click()  Is far more fragile than this… void login(String username, String password) { $("input[name=username]").value(username) $("input[name=pwd]").value(password) $("input[type=submit]").click() } login("user", "password")
  • 17.
    Browser has-a Page Browser.drive{ to GoogleHomePage at GoogleHomePage search.field.value("wikipedia") at GoogleResultsPage assert firstResultLink.text() == "Wikipedia" firstResultLink.click() waitFor { at WikipediaPage } }  The to() and click() methods are changing the underlying page.  You can refer to the current page's content and methods just by name.
  • 18.
    Geb's Page Objects Gebbuilds the Page Object pattern directly into the framework (though it is optional). import geb.* class GoogleHomePage extends Page { static url = "http://google.com/ncr" static at = { title == "Google" } static content = { search { module GoogleSearchModule } } }
  • 19.
    Geb's Page Objects Featuresthe “Content DSL” for naming content in a dynamic and powerful way. import geb.* class GoogleResultsPage extends Page { static at = { waitFor { title.endsWith("Google Search") } } static content = { search { module GoogleSearchModule } results { $("li.g") } result { i -> results[i] } resultLink { i -> result(i).find("a.l", 0) } firstResultLink { resultLink(0) } } }
  • 20.
    Modules Modules are repeating and/or reappearing content. import geb.* class GoogleSearchModule extends Module { static content = { field { $("input", name: "q") } button(to: GoogleResultsPage) { $("input", value: buttonValue) } }
  • 21.
  • 22.
    Geb for Testing Geb can be used with…  Spock  JUnit (3 & 4)  TestNG  EasyB  Cucumber (Cuke4Duke)  The majority of Geb users use Spock.  Geb can dump HTML and screenshots for each “test” to help in debugging.
  • 23.
    Navigator API jQuery inspiredcontent selection/navigation
  • 24.
    Attribute/Text match Can matchon attribute values:  //<div foo="bar">  $("div", foo: "bar")  The “text” attribute is special:  //<div>foo</div>  $("div", text: "foo") Can use Regular Expressions:  //<div>foo</div>  $("div", text: ~/f.+/)
  • 25.
    Relative Content  $()returns a Navigator that allows you to find relative content. $("p").previous() $("p").prevAll() $("p").next() $("p").nextAll() $("p").parent() $("p").siblings() $("div").children()  Most of these methods take selectors, indexes and attribute text/matchers too. $("p").nextAll(".listing")
  • 26.
  • 27.
    Content DSL class GoogleResultsPageextends Page { static content = { results { $("li.g") } result { i -> results[i] } resultLink { i -> result(i).find("a.l", 0) } firstResultLink { resultLink(0) } } } Content definitions can build upon each other. Content definitions are actually templates.
  • 28.
    Optional Content class OptionalPageextends Page { static content = { errorMsg(required: false) { $("p.errorMsg") } } } By default, Geb will error if the content you select doesn't exist. The “required” option disables this check.
  • 29.
    Dynamic Content class DynamicPageextends Page { static content = { errorMsg(wait: true) { $("p.errorMsg") } } }  Geb will wait for some time for this content to appear.  By default, it will look for it every 100ms for 5s before giving up. This is highly configurable.  Same semantics as the waitFor {} method that can be used anywhere.
  • 30.
    Expensive Content class ExpensivePageextends Page { static content = { results(cache: true) { $("li.results") } result { results[it] } } }  By default, all content is transient.  The cache option instructs Geb to hold on to the content, avoiding redundant lookups.  Use carefully, can cause problems with dynamic pages.
  • 31.
  • 32.
    The to() method classGoogleHomePage extends Page { static url = "http://google.com/ncr" } Pages can define a url that defines the page location. The to() method sends the browser there and sets that as the current page object.
  • 33.
    Content based navigation classFrontPage { static content = { aboutUsLink(to: AboutUsPage) { $("div#nav ul li a", text: iStartsWith("About Us")) } } } When this content is clicked, the underlying page will be changed implicitly. to FrontPage aboutUsLink.click() page instanceof AboutUsPage
  • 34.
    At Checking The “atchecking” mechanism enables fail fast and less debugging. class LoginPage extends Page { static at = { $("h1").text() == "Please log in" } } browser.at LoginPage Will throw an exception if every statement of the at check is not true.
  • 35.
    Driver Management Geb cachesthe WebDriver instance (per thread) and shares it across test cases. Manages clearing cookies and is configurable.
  • 36.
    Config. Management Looks GebConfig.groovyfile on classpath. driver = { new FirefoxDriver() } waiting { timeout = 2 slow { timeout = 100 } } reportsDir = "geb-reports“ environments { chrome { driver = "chrome" } }
  • 37.
  • 38.
    Summary JUnit4 Spock Grails TestNG EasyB
  • 39.
    Thanks  @gaurav_bansal  gbansal@xebia.com /