The best way to handle repeating content (tables/search results/etc...) in Geb is with a Module. Example from the Book of Geb:
class CartRow extends Module {
static content = {
cell { $("td", it) }
productName { cell(0).text() }
quantity { cell(1).text().toInteger() }
price { cell(2).text().toDouble() }
}
}
And define a list of CartRows in our Page:
class CheckoutPage extends Page {
static content = {
cartItems { moduleList CartRow, $("table tr").tail() } // tailing to skip the header row
}
}
Because the return value of cartItems is a list of CartRow instances, we can use any of the usual collection methods:
assert cartItems.every { it.price > 0.0 }
I also have a working example of this in my Geb Examples project on GitHub...