In my application, some of the Geb tests are a bit flaky since we're firing off an ajax validation http request after each form field changes. If the ajax call doesn't return fast enough, the test blows up.
I wanted to test a simple solution for this, which (rightly or wrongly, let's not get into that debate here...) is to introduce a short 100ms or so pause after each field is set, so I started looking at how & where I could make this happen.
It looks like I need to add a Thread.sleep
after the NonEmptyNavigator.setInputValue
and NonEmptyNavigator.setSelectValue
methods are invoked. I created a subclass of GebSpec
, into which I added a static initializer block:
static {
NonEmptyNavigator.metaClass.invokeMethod = { String name, args ->
def m = delegate.metaClass.getMetaMethod(name, *args)
def result = (m ? m.invoke(delegate, *args) : delegate.metaClass.invokeMissingMethod(delegate, name, args))
if ("setInputValue".equals(name) || "setSelectValue".equals(name)) {
Thread.sleep(100)
}
return result
}
}
However I added some debug logging, and I noticed that when I execute my spec I never hit this code. What am I doing wrong here...?
I know you asked not to get into a debate about putting sleeps whenever you set a form element value but I just want to assure you that this is really something you don't want to do. There are two reasons:
If you really insist on doing it this way then Geb allows you to use custom Navigator
implementations. Your custom non empty Navigator
implementation would look like this:
class ValueSettingWaitingNonEmptyNavigator extends NonEmptyNavigator {
Navigator value(value) {
super.value(value)
Thread.sleep(100)
this
}
}
This way there's no need to monkey-patch NonEmptyNavigator
and you will avoid any strange problems that might cause.
A proper solution would be to have a custom Module
implementation that would override Navigator value(value)
method and use waitFor()
to check if the validation has completed. Finally you would wrap all your validated form elements in this module in your pages and modules content
blocks. This would mean that you only wait where it's necessary and as little as possible. I don't know how big your suite is but as it will grow these 100ms will turn into minutes and you will be upset about how slow your tests are. Believe me, I've been there.