Date comparison issue?

63 views
Skip to first unread message

Brian Westrich

unread,
Aug 10, 2016, 11:53:51 AM8/10/16
to Geb User Mailing List, Andreas Hochrein
Hello Geb users!

I'm really enjoying using Geb for testing, and especially appreciate the informative error messages that Geb/Spock gives when tests fail. 

Today we came across a possible exception to this rule. We found that if a date comparison fails, the actual date value is not displayed, instead we get a StaleElementReference exception as shown below..... 

labRequest[0].dateField == requestDate
|         |   |         |  |
|         |   |         |  2016-03-02T00:00
|         |   |         false
|         |   geb.content.SimplePageContent@a4f7aef (renderer threw StaleElementReferenceException)
|         gov.bhnrc.modules.LabAnalysisRequestRow@2d4bfa3f (renderer threw StaleElementReferenceException)
java.util.ArrayList@7fc57d59 (renderer threw GroovyRuntimeException)

We define the date field in the Page Object as follows: 
dateField { $("div span input[name=dateSent]") }

and then do the comparison as follows: 
def requestDate = '2016-03-02T00:00'
...
labRequest[0].dateField == requestDate

If the values of the two dates match, the test passes, but if they differ then the above exception occurs. 

I did a brief search through the recent mailing list archives, but didn't see anything mentioned similar to this. 

Has anyone else run across this? 

-- Brian 


Raviteja Lokineni

unread,
Aug 10, 2016, 2:56:59 PM8/10/16
to geb-...@googlegroups.com
StaleElementReferenceException usually occurs when you update the DOM but fail to set the page element to cache: false, wait: true.

http://www.gebish.org/manual/current/#code-cache-code

This happened in my case a few years ago. Not sure what might be happening in your case but do check for DOM updates.

--
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+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/geb-user/99732e0a-fda7-43dd-8523-be93e37d73f5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Raviteja Lokineni | Business Intelligence Developer
TD Ameritrade


Marcin Erdmann

unread,
Aug 10, 2016, 4:09:23 PM8/10/16
to Geb User Mailing List
Hi Brian,

The error you're seeing is very interesting - it means that the elements that are reported on are removed from DOM between the comparison fails and the values of elements of the comparison are being printed. If they were removed before the comparison happened then you would get a StaleElementReferenceException instead of the exception being part of the comparison failure message. That's quite an edge case, but I've seen similar things in the past.

Anyway, the action that you are executing just before the assertion you shared happens has to trigger asynchronous removal of some DOM elements that are evaluated in that assertion. What is happening before this statement is being executed? Are you using some js framework intended for building single page apps like Angular, Ember or React? If that is the case then you will have to add an waitFor() call which will enable you to wait for the page state to stabilise before moving on with performing your assertion.

Marcin

Brian Westrich

unread,
Aug 12, 2016, 3:11:21 PM8/12/16
to geb-...@googlegroups.com
On Wed, Aug 10, 2016 at 3:09 PM, Marcin Erdmann <marcin....@proxerd.pl> wrote:
>
> Are you using some js framework intended for building single
> page apps like Angular, Ember or React? If that is the case then you will
> have to add an waitFor() call which will enable you to wait for the page
> state to stabilise before moving on with performing your assertion.
>

Thanks for the suggestion Marcin. We ARE using Angular. I added a waitFor, and this changed the error message slightly, but it still doesn't behave as I'd hoped (it merely reports that the actual date is null, vs. showing the value of the actual date. Here's the output below:

Condition not satisfied:


labRequest[0].dateField == requestDate
|         |   |         |  |
|         |   |         |  2016-03-02T00:00
|         |   |         false
|         |   geb.content.SimplePageContent@6add684e (renderer threw StaleElementReferenceException)
|         ......LabAnalysisRequestRow@274eff2c (renderer threw StaleElementReferenceException)
java.util.ArrayList@1e76c657 (renderer threw GroovyRuntimeException)

Do you have any other suggestions?  Should I report this on the geb developer's mailing list and/or enter it as a defect?

Marcin Erdmann

unread,
Aug 14, 2016, 3:57:55 PM8/14/16
to Geb User Mailing List
Brian, from what you wrote until now I don't think that this is a defect with Geb, so let's continue trying to figure out what is going on in this thread for now.

You're talking about the value of date being reported as null after introducing a waitFor() call but the output you included looks exactly the same to me as in the initial email from you. Did you make a mistake and include the old report instead of the new one? Can you also please show how you used the waitFor() method?

--
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+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.

Brian Westrich

unread,
Aug 15, 2016, 3:32:32 PM8/15/16
to geb-...@googlegroups.com
On Sun, Aug 14, 2016 at 2:57 PM, Marcin Erdmann
<marcin....@proxerd.pl> wrote:
>
> Did you make a mistake and include the old report instead of the new one? Can you also please show how you used the waitFor() method?


Marcin,

You are correct that the two test failure reports that I posted are
identical. I didn't notice they were the same when I posted the 2nd
report.

Here's how I coded the waitFor....
waitFor {
labRequest[0].labNameField.value()
}
labRequest[0].dateField == requestDate

As coded above, the test passes if the two dates to be compared are
equal, and throws a StaleElementException if the two dates are not
equal.

A colleague of mine had coded the waitFor a different way and gotten a
different test failure report than mine, but he's not available for
the next month or so (traveling to a different country) so I can't ask
him the way he coded the waitFor.

Does the way I coded it look correct to you?


Brian

Marcin Erdmann

unread,
Aug 17, 2016, 4:44:28 PM8/17/16
to Geb User Mailing List
Brian,

The fact that you are getting these exceptions means that the content you are accessing is removed from DOM between the evaluation and reporting. So I can see the following options:
- the content you are accessing is being replaced constantly in the page
- your waitFor condition passes before the page state has stabilised

What happens if you wrap your failing condition in a waitFor:

waitFor { labRequest[0].dateField == requestDate }

Of course, this is not the end solution because you don't want to wait that long for the failure but if you please could try it and share the result then it would help in debugging this.

One more thing, Is this code you shared coming from test, a page class or a module class? This is important due to modules having base navigator which might get stale. But if that was the case then I'd expect the error you're seeing to be different.

Also, can you please share which version of Spock you are using?

--
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+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.

Brian Westrich

unread,
Aug 18, 2016, 2:15:04 PM8/18/16
to geb-...@googlegroups.com
On Wed, Aug 17, 2016 at 3:44 PM, Marcin Erdmann
<marcin....@proxerd.pl> wrote:
>
> What happens if you wrap your failing condition in a waitFor:
>
> waitFor { labRequest[0].dateField == requestDate }
>

The test waits for 30 seconds, then fails.

condition did not pass in 30.0 seconds (failed with exception)
.....
Caused by: Assertion failed:

labRequest[0].dateField == requestDate
| | | | |
| | | | 2016-03-02T00:00
| | | false
| | dateField - SimplePageContent (owner: labRequest -
LabAnalysisRequestRow (owner: ProjectDetailPage, args: [], value:
null), args: [], value: 2016-02-03T00:00)
| labRequest - LabAnalysisRequestRow (owner:
ProjectDetailPage, args: [], value: null)
[labRequest - LabAnalysisRequestRow (owner: ProjectDetailPage, args:
[], value: null)]


>
> Is this code you shared coming from test, a page class or a module class?

A test

>
> Also, can you please share which version of Spock you are using?


org.spockframework:spock-core:1.0-groovy-2.4

Brian Kotek

unread,
Aug 18, 2016, 2:41:58 PM8/18/16
to Geb User Mailing List
Isn't the answer right there in the debug output? The value of dateField is "2016-02-03T00:00" but the value of requestDate is "2016-03-02T00:00". They aren't equal, so the assertion failure is correct.

--
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+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.

Brian Westrich

unread,
Aug 18, 2016, 6:45:54 PM8/18/16
to geb-...@googlegroups.com
Brian,

You are right that the expected value is listed in the debug output.

What's curious is that, when the comparison (between actual and
expected values) fails, I only see the expected value if I use a
waitFor() as suggested by Marcin. If I don't use waitFor(), I instead
get a StaleElementReferenceException and the expected value isn't
shown (though, as noted previously, if the comparison succeeds, the
waitFor isn't needed for the test to pass).

Another curiousity: If I pass in a smaller value for the timeout (say
1 second), geb still shows the expected value on failure, but I don't
have to wait the default duration of 30 seconds. Instead, Geb shows
the expected value after only 1 second of waiting:

waitFor(1) {
labRequest[0].dateField == requestDate
}

Output:

condition did not pass in 1.0 seconds (failed with exception)
geb.waiting.WaitTimeoutException: ......
...
Caused by: Assertion failed:

labRequest[0].dateField == requestDate
| | | | |
| | | | 2016-03-02T00:00
| | | false
| | dateField - SimplePageContent (owner: labRequest -
LabAnalysisRequestRow (owner: ProjectDetailPage, args: [], value:
null), args: [], value: 2016-02-03T00:00)
| labRequest - LabAnalysisRequestRow (owner:
ProjectDetailPage, args: [], value: null)
[labRequest - LabAnalysisRequestRow (owner: ProjectDetailPage, args:
[], value: null)]

So it looks like, in this case, some waiting period is needed before
geb is able to fully report test error information, but not for geb to
process a successful comparison.

Incidentally, I thought this behavior might only be occurring for date
fields, but have verified it occurs for other types of fields as well
(e.g. string).

Brian W.

Marcin Erdmann

unread,
Aug 22, 2016, 3:53:03 PM8/22/16
to Geb User Mailing List
Brian,

One thing that I don't understand is why you see a different behaviour if the condition is fulfilled (i.e. there is no StaleElementReferenceException) and when it is not. Is it the case that the value of the date field does not change when your test passes? The fact that you are getting the exception stems most probably from the fact that the DOM is still updating while the condition is being checked.

A slightly better way of avoiding the exception would be to wrap the extraction of the element value in a waitFor:

waitFor { labRequest[0].dateField.value() } == requestDate

This way you will utilise the fact that waitFor() retries if there is an exception thrown from the closure passed to it.

Anyhow you should probably use a better wait for condition to wait for the page to stabilise after performing the action that triggers DOM updates. The one you shared previously, that is waitFor { labRequest[0].labNameField.value() }, clearly did not work given the behaviour you observed after introducing it.

--
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+unsubscribe@googlegroups.com.
To post to this group, send email to geb-...@googlegroups.com.

Brian Westrich

unread,
Aug 22, 2016, 6:02:51 PM8/22/16
to geb-...@googlegroups.com
On Mon, Aug 22, 2016 at 2:53 PM, Marcin Erdmann
<marcin....@proxerd.pl> wrote:
> Brian,
>
> One thing that I don't understand is why you see a different behaviour if
> the condition is fulfilled (i.e. there is no StaleElementReferenceException)
> and when it is not. Is it the case that the value of the date field does not
> change when your test passes?

Yes, the value of the field does not change.


> A slightly better way of avoiding the exception would be to wrap the
> extraction of the element value in a waitFor:
>
> waitFor { labRequest[0].dateField.value() } == requestDate
>
> This way you will utilise the fact that waitFor() retries if there is an
> exception thrown from the closure passed to it.

I agree. Here's what I ended up using (slightly different from your
suggestion above, but I think it follows the spirit):

waitFor(0) {
labRequest[0].dateField == requestDate
}

Using this, when the comparison succeeds, the test passes. When the
comparison fails, the test immediately fails and geb shows the
expected and actual value:

condition did not pass in 0.0 seconds (failed with exception)
.....
Caused by: Assertion failed:

labRequest[0].dateField == requestDate
| | | | |
| | | | 2016-02-02T00:00
| | | false
| | dateField - SimplePageContent (owner: labRequest -
LabAnalysisRequestRow (owner: ProjectDetailPage, args: [], value:
null), args: [], value: 2016-02-03T00:00)
......

Of course, this isn't a general solution, as if possible we don't want
to put waitFor's around all our assertions.

>
> Anyhow you should probably use a better wait for condition to wait for the
> page to stabilise after performing the action that triggers DOM updates. The
> one you shared previously, that is waitFor {
> labRequest[0].labNameField.value() }, clearly did not work given the
> behaviour you observed after introducing it.

You are correct. The one I shared previously was incorrect, a
cut/paste mistake on my part. Thank you for catching this.

Thanks for all your expertise contributed on this email thread.
Reply all
Reply to author
Forward
0 new messages