Permalink
Browse files

Migrated Markdown to AsciiDoc

  • Loading branch information...
bodiam committed Jan 24, 2015
1 parent 2d31f10 commit b01ec2710c83540e2008f65ed07b5b80de5e440d
@@ -0,0 +1,275 @@
+= Introduction
+
+Geb is a developer focused tool for automating the interaction between web browsers and web content. It uses the dynamic language features of {groovy} to provide a powerful content definition DSL (for modelling content for reuse) and key concepts from {jquery} to provide a powerful content inspection and traversal API (for finding and interacting with content).
+
+Geb was born out of a desire to make browser automation (originally for web testing) easier and more productive. It aims to be a *developer tool* in that it allows and encourages the using of programming and language constructs instead of creating a restricted environment. It uses Groovy's dynamism to remove the noise and boiler plate code in order to focus on what's important — the content and interaction.
+
+== The Browser Automation Technology
+
+Geb builds on the {webdriver} browser automation library, which means that Geb can work with http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_Which_browsers_does_support?[any browser that WebDriver can]. While Geb provides an extra layer of convenience and productivity, it is always possible to “drop down” to the WebDriver level to do something directly should you need to.
+
+For more information see the manual section on link:driver.html[using a driver implementation].
+
+== The Page Object Pattern
+
+The Page Object Pattern gives us a common sense way to model content in a reusable and maintainable way. From the http://code.google.com/p/selenium/wiki/PageObjects[WebDriver wiki page on the Page Object Pattern]:
+
+____
+
+Within your web app's UI there are areas that your tests interact with. A Page Object simply models these as objects within the test code. This reduces the amount of duplicated code and means that if the UI changes, the fix need only be applied in one place.
+
+____
+
+Furthermore (from the same document):
+
+____
+
+PageObjects can be thought of as facing in two directions simultaneously. Facing towards the developer of a test, they represent the services offered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page) It's simplest to think of the methods on a Page Object as offering the "services" that a page offers rather than exposing the details and mechanics of the page. As an example, think of the inbox of any web-based email system. Amongst the services that it offers are typically the ability to compose a new email, to choose to read a single email, and to list the subject lines of the emails in the inbox. How these are implemented shouldn't matter to the test.
+
+____
+
+The Page Object Pattern is an important technique, and Geb provides first class support via its link:pages.html[page] and link:modules.html[module] constructs.
+
+== The jQuery-ish Navigator API
+
+The {jquery} JavaScript library provides an excellent API for (among other things) selecting or targeting content on a page and traversing through and around content. Geb takes a lot of inspiration from this.
+
+In Geb, content is selected through the `$` function, which returns a [`Navigator`][navigator-api] object. A [`Navigator`][navigator-api] object is in someways analogous to the `jQuery` data type in jQuery in that it represents one or more targeted elements on the page.
+
+Let's see some examples:
+
+----
+// match all 'div' elements on the page
+$("div")
+
+// match the first 'div' element on the page
+$("div", 0)
+
+// match all 'div' elements with a title attribute value of 'section'
+$("div", title: "section")
+
+// match the first 'div' element with a title attribute value of 'section'
+$("div", 0, title: "section")
+
+// match all 'div' elements who have the class 'main'
+$("div.main")
+
+// match the first 'div' element with the class 'main'
+$("div.main", 0)
+----
+
+These methods return `Navigator` objects that can be used to further refine the content.
+
+----
+// The parent of the first paragraph
+$("p", 0).parent()
+
+// All tables with a cellspacing attribute value of 0 that are nested in a paragraph
+$("p").find("table", cellspacing: '0')
+----
+
+This is just the beginning of what is possible with the Navigator API. See the {navigator} for more details.
+
+== Full Examples
+
+Let's have a look at a simple case of wanting to search for “wikipedia” on Google and follow the first result returned.
+
+=== Inline Scripting
+
+Here's an example of using Geb in an inline (i.e. no page objects or predefined content) scripting style…
+
+----
+import geb.Browser
+
+Browser.drive {
+ go "http://google.com/ncr"
+
+ // make sure we actually got to the page
+ assert title == "Google"
+
+ // enter wikipedia into the search field
+ $("input", name: "q").value("wikipedia")
+
+ // wait for the change to results page to happen
+ // (google updates the page dynamically without a new request)
+ waitFor { title.endsWith("Google Search") }
+
+ // is the first link to wikipedia?
+ def firstLink = $("li.g", 0).find("a.l")
+ assert firstLink.text() == "Wikipedia"
+
+ // click the link
+ firstLink.click()
+
+ // wait for Google's javascript to redirect to Wikipedia
+ waitFor { title == "Wikipedia" }
+}
+----
+
+=== Scripting with Page Objects
+
+This time let us define our content up front using the Page Object pattern…
+
+----
+import geb.Browser
+import geb.Page
+import geb.Module
+
+// modules are reusable fragments that can be used across pages that can be parameterised
+// here we are using a module to model the search function on the home and results pages
+class GoogleSearchModule extends Module {
+
+ // a parameterised value set when the module is included
+ def buttonValue
+
+ // the content DSL
+ static content = {
+
+ // name the search input control “field”, defining it with the jQuery like navigator
+ field { $("input", name: "q") }
+
+ // the search button declares that it takes us to the results page, and uses the
+ // parameterised buttonValue to define itself
+ button(to: GoogleResultsPage) {
+ $("input", value: buttonValue)
+ }
+ }
+}
+
+class GoogleHomePage extends Page {
+
+ // pages can define their location, either absolutely or relative to a base
+ static url = "http://google.com/ncr"
+
+ // “at checkers” allow verifying that the browser is at the expected page
+ static at = { title == "Google" }
+
+ static content = {
+ // include the previously defined module
+ search { module GoogleSearchModule, buttonValue: "Google Search" }
+ }
+}
+
+class GoogleResultsPage extends Page {
+ static at = { title.endsWith "Google Search" }
+ static content = {
+ // reuse our previously defined module
+ search { module GoogleSearchModule, buttonValue: "Search" }
+
+ // content definitions can compose and build from other definitions
+ results { $("li.g") }
+ result { i -> results[i] }
+ resultLink { i -> result(i).find("a.l") }
+ firstResultLink { resultLink(0) }
+ }
+}
+
+class WikipediaPage extends Page {
+ static at = { title == "Wikipedia" }
+}
+----
+
+Now our script again, using the above defined content…
+
+----
+Browser.drive {
+ to GoogleHomePage
+ assert at(GoogleHomePage)
+ search.field.value("wikipedia")
+ waitFor { at GoogleResultsPage }
+ assert firstResultLink.text() == "Wikipedia"
+ firstResultLink.click()
+ waitFor { at WikipediaPage }
+}
+----
+
+=== Testing
+
+Geb itself does not include any kind of testing or execution framework. Rather, it works with existing popular tools like {spock}, {junit}, {testng} and {cucumber-jvm}. While Geb works well with all of these test tools, we encourage the use of {spock} as it's a great match for Geb with its focus and style.
+
+Here is our Google case again, this time use Geb's {spock} integration…
+
+----
+import geb.spock.GebSpec
+
+class GoogleWikipediaSpec extends GebSpec {
+
+ def "first result for wikipedia search should be wikipedia"() {
+ given:
+ to GoogleHomePage
+
+ expect:
+ at GoogleHomePage
+
+ when:
+ search.field.value("wikipedia")
+
+ then:
+ waitFor { at GoogleResultsPage }
+
+ and:
+ firstResultLink.text() == "Wikipedia"
+
+ when:
+ firstResultLink.click()
+
+ then:
+ waitFor { at WikipediaPage }
+ }
+}
+----
+
+For more information on using Geb for web and functional testing, see the link:testing.html[testing chapter].
+
+== Installation & Usage
+
+Geb itself is a available as a single http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22@geb-group@%22%20AND%20a%3A%22geb-core%22[`geb-core` jar from the central Maven repository]. To get up and running you simply need this jar, a WebDriver driver implementation and the `selenium-support` jar.
+
+Via `@Grab`…
+
+----
+@Grapes([
+ @Grab("@geb-group@:geb-core:@geb-version@"),
+ @Grab("org.seleniumhq.selenium:selenium-firefox-driver:@selenium-version@"),
+ @Grab("org.seleniumhq.selenium:selenium-support:@selenium-version@")
+])
+import geb.Browser
+----
+
+Via Maven…
+
+----
+<dependency>
+ <groupId>@geb-group@</groupId>
+ <artifactId>geb-core</artifactId>
+ <version>@geb-version@</version>
+</dependency>
+<dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-firefox-driver</artifactId>
+ <version>@selenium-version@</version>
+</dependency>
+<dependency>
+ <groupId>org.seleniumhq.selenium</groupId>
+ <artifactId>selenium-support</artifactId>
+ <version>@selenium-version@</version>
+</dependency>
+----
+
+Via Gradle…
+
+----
+compile "@geb-group@:geb-core:@geb-version@", "org.seleniumhq.selenium:selenium-firefox-driver:@selenium-version@", "org.seleniumhq.selenium:selenium-support:@selenium-version@"
+----
+
+Alternatively, if using an integration such as `geb-spock` or `geb-junit4` you can depend on that instead of `geb-core`. You can check out http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22@geb-group@%22[the listing of all artifacts in `@geb-group@` group] to see what's available.
+
+____
+
+Be sure to check the chapter on link:build-integrations.html[build integrations] for information on using Geb with particular environments, like {grails}.
+
+____
+
+=== Snapshot repository
+
+If you fancy living on the bleeding edge then you can try out Geb's snapshot artifacts located in https://oss.sonatype.org/content/repositories/snapshots/@geb-group-dir@[the Maven repository at https://oss.sonatype.org/content/repositories/snapshots].
Oops, something went wrong.

0 comments on commit b01ec27

Please sign in to comment.