Craig Atkinson | Chief Technologist | Object Partners
waitFor {
$("div.alert").displayed
}
assert $("div.alert").text() == "Error creating user"
waitFor {
databaseUtil.userExists('myUsername')
}
loginPage.login('myUsername', 'myPassword')
GebConfig.groovy
// Configure where screenshots are stored
reportsDir = 'build/test-reports'
// Optional, less noise when only failed tests generate screenshots
reportOnTestFailureOnly = true
def cleanup() {
LogEntries logs = driver.manage().logs().get(LogType.BROWSER)
List errorLogEntries = logs.filter(Level.SEVERE)
if (errorLogEntries) {
println "Browser errors:"
errorLogEntries.each { logEntry ->
println("[${logEntry.level}] ${logEntry.message}")
}
}
}
// Intentional Javascript error for demonstrating capturing browser logs
fakeObject.fakeMethod();
Browser errors:
[SEVERE] /author/edit/4 59:13 Uncaught ReferenceError: fakeObject is not defined
class LoginPage extends geb.Page {
static content = {
usernameField { $("#username") }
passwordField { $("#password") }
submitButton(to: DashboardPage) { $("#submit") }
}
}
Standard: Geb delegates method calls to current page object
to HomePage
loginButton.click()
username = "user1"
password = "password1"
submitButton.click()
// What page is the test on now?
// What fields are on the current page?
HomePage homePage = to(HomePage)
LoginPage loginPage = homePage.clickLoginButton()
DashboardPage dashboardPage = loginPage.login("user1", "password1")
HomePage homePage = to(HomePage)
DashboardPage dashboardPage = homePage
.clickLoginButton()
.login("user1", "password1")
class HomePage extends geb.Page {
static content = {
loginButton(to: LoginPage) { $("#loginButton") }
}
LoginPage clickLoginButton() {
loginButton.click()
return browser.page
}
}
class LoginPage extends geb.Page {
static content = {
usernameField { $("#username") }
passwordField { $("#password") }
submitButton(to: DashboardPage) { $("#submit") }
}
DashboardPage login(String username, String password) {
usernameField.value(username)
passwordField.value(password)
submitButton.click()
return browser.page
}
}
Click and drag slider with mouse
static content = {
ratingSliderHandle { $(".ui-slider-handle") }
}
void moveRatingSlider(Integer rating) {
// Slider is 400 pixels wide and starts at 1,
// so each notch above 1 is 100 pixels apart
Integer numPixelsX = (rating - 1) * 100
interact {
clickAndHold(ratingSliderHandle)
moveByOffset(numPixelsX, 0)
release()
}
}
Send keystrokes with left-shift operator <<
$("#myInputField") << "value"
$(".ui-slider-handle") << Keys.ARROW_RIGHT
static content = {
hiddenLink { $("#hiddenLink") }
}
void clickHiddenLink() {
hiddenLink.jquery.show()
hiddenLink.click()
}
def seleniumVersion = "2.53.1"
testCompile "org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}"
testCompile "org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}"
testCompile "org.seleniumhq.selenium:selenium-ie-driver:${seleniumVersion}"
testCompile("io.github.bonigarcia:webdrivermanager:1.4.1")
import io.github.bonigarcia.wdm.ChromeDriverManager
import org.openqa.selenium.chrome.ChromeDriver
environments {
chrome {
ChromeDriverManager.getInstance().setup()
driver = { new ChromeDriver() }
}
}
# src/test/resources/application.properties
wdm.targetPath=build/webdriver
Grails 2
grails -Dgeb.env=chrome test-app functional:
Grails 3
gradle -Dgeb.env=chrome integrationTest
Spring Boot
gradle -Dgeb.env=chrome test
// Pass system properties through to the integrationTest task
// so we can pass in the 'geb.env' property
configure(integrationTest) {
systemProperties System.properties
}
// Pass system properties through to the test task
// so we can pass in the 'geb.env' property
configure(test) {
systemProperties System.properties
}
Idea createIdea(String title, String description) {
RemoteControl remote = new RemoteControl()
remote {
Idea idea = new Idea(
title: title,
description: description
)
idea.save()
}
}
List ideas = (1..5).collect { i ->
ideaRemoteControl.createIdea("Title ${i}", "Description ${i}")
}
Idea findByTitle(String title) {
RemoteControl remote = new RemoteControl()
remote {
Idea.findByTitle(title)
}
}
Tests and app run in same JVM
import grails.test.mixin.integration.Integration
import org.springframework.beans.factory.annotation.Autowired
@Integration
class AuthorGebSpec extends GebReportingSpec {
@Autowired
AuthorDataUtil authorDataUtil
void "should create Author"() {
...
then:
assert authorDataUtil.findByLastName('Last')?.firstName == 'First'
}
}
PatentService sends ideas to patent office
class PatentService {
def sendToPatentOffice(Idea idea) {
// Send the idea to the real patent office
}
}
class PatentServiceMock extends PatentService {
List ideasSentToPatentOffice = []
@Override
def sendToPatentOffice(Idea idea) {
ideasSentToPatentOffice << idea
}
}
beans = {
if (Environment.current == Environment.TEST) {
// Override the PatentService with our mock version when running tests
patentService(PatentServiceMock)
}
}
@Autowired
PatentServiceMock patentService
def 'should submit idea to patent office'() {
given:
Idea idea = ideaRemoteControl.findByTitle('Patentable Idea')
IdeaShowPage ideaShowPage = to([id: idea.id], IdeaShowPage)
when:
ideaShowPage = ideaShowPage.submitIdeaToPatentOffice()
then:
List ideasSubmittedToPatentOffice = patentService.ideasSentToPatentOffice
assert ideasSubmittedToPatentOffice*.id.contains(idea.id)
}