Test fails inconsistently on evaluation of front-end-generated, post-DOMContentLoaded content

49 views
Skip to first unread message

Samuel Rossinovic

unread,
Aug 27, 2017, 11:27:04 PM8/27/17
to Geb User Mailing List
I am testing a single-page app. The app presents a tabbed interface, where clicking on tabs places the user into various "pages". The app indicates the current location through a breadcrumb-like string. E.G. the app would have a main tab called 'Accounts', with multiple nested sub-tabs, "All", "Owing", "Paid-out", etc. So if user clicks "Accounts", then "All", the a/m heading will contain "Accounts - All". Then, if user clicks another sub-tab - say "Owing" - the heading will change to "Accounts - Owing".

The heading is generated in the front end, and is apparently constructed piece by piece (I.E. "" -> "Accounts" -> "Accounts - Owing").
I've written the following content checker:

class Foo extends Page {
   
static content = {
        heading
(wait: true) { $("h1").text() }
   
}
}

class AccountsOwingTab extends Foo {
 
static at = {
   
heading == "Accounts-Owing"
 
}
}    


However, it fails inconsistently, with an error message complaining "Accounts" != "Accounts - Owing" (by "inconsistently", I mean that it would occasionally fail, and pass in other test runs).

I assume what is happening is that the content checker reads the heading in its half-baked status (btw, the report generated at fail time shows that the heading is actually complete, and should have passed the check!). I also assume that wait() would only wait for non-empty content, rather than to wait for matching content. Is there a way around it?

Thanks!

Marcin Erdmann

unread,
Aug 28, 2017, 6:05:02 PM8/28/17
to Geb User Mailing List
Yes there is. Do not specify `wait: true` on your content and wrap your at checker in a wait for call, either explicitly:

static at = {
    waitFor { heading == "Accounts - Owing"
}


--
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/c0b1edcf-aa7d-4462-a82b-7743f423ccdd%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Samuel Rossinovic

unread,
Aug 29, 2017, 5:54:33 AM8/29/17
to Geb User Mailing List
Thank you. This seems to be working :)

I am also experiencing a similar issue with modules: I have a setup not-unlike the one described in the ModuleList() section of the manual. However, in my case, the table rows are loaded asynchronously. I believe that when my test initializes the ModuleList, its base is available, but the table rows aren't. When the test executes something like:
$("table tr").tail().moduleList(CartRow).find { it.productName == "The Book Of Geb"}


it returns 0 objects, whereas if the line is split to:

def cartRows = $("table tr").tail().moduleList(CartRow)
cartRows
.find { it.productName == "The Book Of Geb"}


find *does* yield the expected object.

Is there some module equivalent of at() waiting?

Thanks!

On Tuesday, August 29, 2017 at 8:05:02 AM UTC+10, Marcin Erdmann wrote:
Yes there is. Do not specify `wait: true` on your content and wrap your at checker in a wait for call, either explicitly:

static at = {
    waitFor { heading == "Accounts - Owing"
}

On Mon, Aug 28, 2017 at 4:27 AM, Samuel Rossinovic <samuel.r...@gmail.com> wrote:
I am testing a single-page app. The app presents a tabbed interface, where clicking on tabs places the user into various "pages". The app indicates the current location through a breadcrumb-like string. E.G. the app would have a main tab called 'Accounts', with multiple nested sub-tabs, "All", "Owing", "Paid-out", etc. So if user clicks "Accounts", then "All", the a/m heading will contain "Accounts - All". Then, if user clicks another sub-tab - say "Owing" - the heading will change to "Accounts - Owing".

The heading is generated in the front end, and is apparently constructed piece by piece (I.E. "" -> "Accounts" -> "Accounts - Owing").
I've written the following content checker:

class Foo extends Page {
   
static content = {
        heading
(wait: true) { $("h1").text() }
   
}
}

class AccountsOwingTab extends Foo {
 
static at = {
   
heading == "Accounts-Owing"
 
}
}    


However, it fails inconsistently, with an error message complaining "Accounts" != "Accounts - Owing" (by "inconsistently", I mean that it would occasionally fail, and pass in other test runs).

I assume what is happening is that the content checker reads the heading in its half-baked status (btw, the report generated at fail time shows that the heading is actually complete, and should have passed the check!). I also assume that wait() would only wait for non-empty content, rather than to wait for matching content. Is there a way around it?

Thanks!

--
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.

Samuel Rossinovic

unread,
Aug 30, 2017, 2:06:28 AM8/30/17
to Geb User Mailing List
Another example of the same problem. Relying on a <span> with a particular class, that gets added to the DOM at the end of the build-out of a list, a Module waits for this class to appear:

class ListOfItems extends Module {

   
def getItems() {
        waitFor
{ $(".class-that-gets-added-to-the-last-item-of-the-list") }
        $
("li").moduleList(Item)
   
}
}

(initially, I had 'items' as module content, but since I don't know how to wait() for module content, I pushed it down to a method)

The above fails (most of the time), with "WaitTimeoutException: condition did not pass in 5.0 seconds".

If I prepend 'sleep 2000' before the waitFor directive, test never fails (I.E. the waitFor() block actually passes assertion, and the test flows through).

Marcin Erdmann

unread,
Sep 3, 2017, 5:31:44 PM9/3/17
to Geb User Mailing List
You can use content wait option (http://www.gebish.org/manual/current/#content-dsl-wait) to wait for content not to be empty:

static content = {
    cartRows(wait: true) { $("table tr").tail().moduleList(CartRow)}
}

and then use

cartRows.find { it.productName == "The Book Of Geb"}

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.

Marcin Erdmann

unread,
Sep 3, 2017, 5:37:12 PM9/3/17
to Geb User Mailing List
This approach looks correct to me. The error you're getting simply tells you that it sometimes takes more than 5 seconds for the content to appear but if you wait for 7 seconds (by adding that sleep) then all is well. You should just increase the waiting time for that particular waitFor call, see the section on waiting in the Book of Geb for an explanation of how to do it: http://www.gebish.org/manual/current/#waiting.

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.
Reply all
Reply to author
Forward
0 new messages