Geb's page objects don't prevent one
from making higher-level methods to abstract the WebDriver API, so
I don't think it's a matter of something that Geb is doing. I
haven't tried using an inner trait for that, so I'm not sure about
the trade-offs. I guess it would give one some static type
safety, but a false sense of safety, because it would seem to
apply to the whole test class, but I wouldn't expect it to work
unless the test were on the right page at the time.
For comparison, I use a page property with a closure, which I
expect will be dynamically available where it is relevant in the
test:
import grails.util.Holders as CH
class CasLoginPage extends Page {
static at = { title == "University of Hawaii Web Login Service" }
def login = { testuser ->
$("input", name: "username").value( testuser )
$("input", name: "password").value(casTestPassword())
$("input", value: "Login").click()
}
private static casTestPassword() {
def pw = System.getProperty('casTestPassword', CH.config?.cas?.test?.password ?: null)
if (!pw) {
def configMethods = [
'* define cas.test.password="xxx" in $HOME/grails-conf/taps-secret-config.groovy, or',
'* for running in IDE without Grails, use JVM option -DcasTestPassword=xxx'
]
throw new IllegalStateException('configure password xxx for Load Testing CAS like so:\n' + configMethods.join('\n'))
}
pw
}
}
My tests can use it like this:
def "main menu requires CAS login"() {
when:
via MainMenuPage
then:
at CasLoginPage
}
def "can login as an hourly employee"() {
given:
assert at(CasLoginPage)
when:
login( emplData.username )
then:
at MainMenuPage
displayName == emplData.name
However, I wouldn't add levels of abstraction that don't reduce
duplicate code or clarify the test. My tests often call click()
directly on content, and use locators directly. Abstracting the
content locator in a Page class makes sense if it makes the test
easier to read, and allows for changing multiple uses of the
locator in one place in case the HTML/CSS changes. But, what good
would it do to abstract the click() call? Would it make the test
more clear?
def "can get choices of old pay period"() {
given:
assert at(MainMenuPage)
when: 'revealing inactive appointments to choose from'
previousAppointmentsLink?.click()
and: 'selecting an hourly Appointment with an empty previous period'
$("label", text: contains((String) emplData.plcSummary)).click()
and: 'creating for other than the current period (so this spec can use static dates)'
createOtherTimesheetButton.click()
then:
at EmployeeCreateTimesheetForOtherPeriodPage
$("#payPeriod\\.id option").size() > 1
}
Cheers,
11011011