I am trying to make life a bit easier for my userbase. I allow things like:
===
then: "Establish Contact Details"
withFlowViewForm('contactDetailsCheck') { form ->
form.noPhone = true
form.anonymous = true
form.clickCustomRadioButtonHavingNameAndText('caller', cfg.caller)
form.clickNextButton()
}
===
Obviously, clickCustomRadioButtonHavingNameAndText and clickNextButton are not standard Geb/Selenium methods…
Inside ‘withFlowViewForm’, I add clickCustomRadioButtonHavingNameAndText, clickNextButton (and more) closures to the ‘form’ INSTANCE metaClass:
===
void withFlowViewForm(view, c) {
withFrame('iframe') {
final form = $('form')
// inefficient, but simple and works
form.metaClass.clickNextButton = { clickButton(delegate, 'next') }
form.metaClass.clickCustomRadioButtonHavingNameAndText = { name, text ->
def radio = delegate.find('label.form-check-label', text: text).parent().find('input', name: name).module(RadioButtons)
if (radio.isEmpty())
throw new LightweightException("Could not find radio button with {name: ${name}, text: ${text}}")
radio.click()
}
c(form)
}
}
private void clickButton(form, evt) {
report "${form.parent('body').attr('id')}"
def btn = form."_eventId_${evt}"()
if (btn.isEmpty())
throw new LightweightException("Could not find button with {attribute: _eventId_${evt}}")
btn.click()
}
===
This works very nicely, but I can’t help but feel that there should be a more efficient way of doing this…ideally, I would like to decorate ‘form’ one time only at startup (perhaps in GebConfig?).
I have read the doco section: “7.2.2. Navigator factory” is this the way to go? Provide an extension of Navigator?
I like that the doco says “..get in touch via the mailing list if you need help.”
Here I am 😊
Can anybody guide me?
Thanks,
BOB
--
You received this message because you are subscribed to the Google Groups "Geb User Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to geb-user+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/geb-user/SY4P282MB1883F0917C84AD9F3210D85EEDB69%40SY4P282MB1883.AUSP282.PROD.OUTLOOK.COM.
Thanks for the response.
I didn’t try page objects for this.
I’m just letting the users do basic scripting…they seem to be happy with that and I don’t think that they would cope too well with too much ‘rigor’…
Wouldn’t a page also decorate each instance? If so it is probably just a potentially cleaner equivalent to what I am already doing?
Also not too sure how to use a page in this situation!
The doco does say “While not as crosscutting as using a custom navigator factory it’s also possible to decorate navigators with additional methods by creating modules based on them.”
So maybe:
final form = $('form').module(MyModuleWithMethodsDefined)
Still on a per-instance basis but this would probably be lighter-weight than all the metaClass stuff I am doing now.
Worth trying???
BOB
To view this discussion on the web visit https://groups.google.com/d/msgid/geb-user/b958f621-646e-9598-a981-f3cdae54648f%40getsu.com.
Well…that was interesting!
Here’s where I have ended up:
===
void withFlowViewForm(view, c) {
withFrame('iframe') {
// Useful for debugging:
// println $('body').getAttribute("outerHTML")
final id = $('body').@id
waitFor(message: "Could not find body with id==${view}, found: ${id}") { id == view }
c($('form').module(new FlowFormDecoratorModule(id: id, report: { msg -> report msg })))
}
}
class FlowFormDecoratorModule extends Module {
String id
def report
def clickNextButton() { clickButton(navigator, 'next') }
[...elided..]
private void clickButton(form, evt) {
report id
def btn = form."_eventId_${evt}"()
if (btn.isEmpty())
throw new LightweightException("Could not find button with {attribute: _eventId_${evt}}")
btn.click()
}
}
===
I ASSUME(/hope) that this is more ‘performant’ than the metaClass-hacking that I did before(…?)
It’s a bit cleaner code, so that’s a ‘win’, regardless…
The one ‘wrinkle’ I found: if I used ‘browser.report’ within FlowFormDecoratorModule, it produced different results to when I used ‘report’ from within withFlowViewForm.
This may have something to do with the fact that I am also using geb-spock-reports.
Outside the module (directly within withFlowViewForm for example) I would end up with a PNG image named very specifically, and based on more than just the report parameter value like: 001-002-EXXXXX__Cold_Water__Reason_For_Call__Normal_Path-fred.png.
Within the module, I couldn’t just call ‘report’ and if I called “browser.report ‘fred’”, I would simply get ‘fred.PNG (which didn’t play well with geb-spock-reports).
That’s why I pass a ‘report’ closure as parameter to the module: it lets me use the ‘good’ report instance…
Thanks to J. David Beutel for planting the seed…
BOB
To view this discussion on the web visit https://groups.google.com/d/msgid/geb-user/SY4P282MB1883301A6C769150B96D369BEDB69%40SY4P282MB1883.AUSP282.PROD.OUTLOOK.COM.
I have read the doco section: “7.2.2. Navigator factory” is this the way to go? Provide an extension of Navigator?
I like that the doco says “..get in touch via the mailing list if you need help.”
Here I am 😊
The doco does say “While not as crosscutting as using a custom navigator factory it’s also possible to decorate navigators with additional methods by creating modules based on them.”
So maybe:
final form = $('form').module(MyModuleWithMethodsDefined)
I ASSUME(/hope) that this is more ‘performant’ than the metaClass-hacking that I did before(…?)
It’s a bit cleaner code, so that’s a ‘win’, regardless…
The one ‘wrinkle’ I found: if I used ‘browser.report’ within FlowFormDecoratorModule, it produced different results to when I used ‘report’ from within withFlowViewForm.
This may have something to do with the fact that I am also using geb-spock-reports.
Outside the module (directly within withFlowViewForm for example) I would end up with a PNG image named very specifically, and based on more than just the report parameter value like: 001-002-EXXXXX__Cold_Water__Reason_For_Call__Normal_Path-fred.png.
Within the module, I couldn’t just call ‘report’ and if I called “browser.report ‘fred’”, I would simply get ‘fred.PNG (which didn’t play well with geb-spock-reports).
That’s why I pass a ‘report’ closure as parameter to the module: it lets me use the ‘good’ report instance…
Thanks to J. David Beutel for planting the seed…
That’s why I pass a ‘report’ closure as parameter to the module: it lets me use the ‘good’ report instance…
This is because outside of the module you are not calling Browser.report(), you are actually calling GebReportingSpec.report() which prepends the report name with some counters and the name of the current test. If you're on Geb 5 then you could pass testManager to your module and call report() on that - testManager is an instance of geb.test.GebTestManager and GebReportingSpec actually delegates the report() method to it.
Nice background info and suggestion. Worked like a charm. Thanks.
BOB