Could not initialize class geb.navigator.NonEmptyNavigator

614 views
Skip to first unread message

Kenneth Kalmer

unread,
Oct 6, 2015, 12:06:41 PM10/6/15
to Geb User Mailing List
Dear readers

We're helping a team retrofit various degrees of tests and other code quality measures on an old production Grails site. One of the things we're doing is writing functional tests using Geb to help get better coverage faster. The end goal is to be in a position where we can start refactoring and upgrading everything to have a high quality system.

That said, I'm completely new to Grails, Groovy and the entire ecosystem. I'm managing to work around many of the issues with a simple RTFM, but this issue has me completely flummoxed.

Background:

Grails: 2.2.4
Groovy: 2.4.5
Geb: 0.10 ;(
Selenium (support & Firefox driver): 2.47.1
Firefox: 41.0.1
OS: Mac 10.10 (Yosemite)

My GebConfig.groovy has been reduced to this:

driver = "firefox"
baseNavigatorWaiting = true
atCheckWaiting = true

The test is as simple as this:

class LoginTest extends GebReportingTest {

 @Test
 void testLoginFailure() {
   to LoginPage

   $("form").username = "foo"
   // Omitted as it doesn't get past here
 }
} 

The stacktrace for the failure is the following:

| Failure:  testLoginFailure(LoginTest)
|  geb.waiting.WaitTimeoutException: condition did not pass in 5.0 seconds (failed with exception)
at geb.waiting.Wait.waitFor(Wait.groovy:124)
at geb.navigator.factory.BrowserBackedNavigatorFactory.getBase(BrowserBackedNavigatorFactory.groovy:39)
at geb.content.NavigableSupport.getBase(NavigableSupport.groovy:31)
at geb.content.NavigableSupport.$(NavigableSupport.groovy:63)
at geb.content.PageContentTemplateFactoryDelegate.$(PageContentTemplateFactoryDelegate.groovy:118)
at pages.LoginPage$__clinit__closure2_closure3.doCall(LoginPage.groovy:10)
at geb.content.PageContentTemplate.invokeFactory(PageContentTemplate.groovy:97)
at geb.content.PageContentTemplate$_create_closure1.doCall(PageContentTemplate.groovy:59)
at geb.content.PageContentTemplate.create(PageContentTemplate.groovy:82)
at geb.content.PageContentTemplate.get(PageContentTemplate.groovy:54)
at geb.content.PageContentSupport.getContent(PageContentSupport.groovy:43)
at geb.content.PageContentSupport.propertyMissing(PageContentSupport.groovy:59)
at geb.Page.propertyMissing(Page.groovy:77)
at pages.LoginPage.login(LoginPage.groovy:18)
at geb.Browser.methodMissing(Browser.groovy:203)
at geb.junit4.GebTest.methodMissing(GebTest.groovy:53)
at LoginTest.testLoginFailure(LoginTest.groovy:11)
Caused by: java.lang.NoClassDefFoundError: Could not initialize class geb.navigator.NonEmptyNavigator
at geb.navigator.factory.DefaultInnerNavigatorFactory.createNavigator(DefaultInnerNavigatorFactory.groovy:39)
at geb.navigator.factory.AbstractNavigatorFactory.createFromWebElements(AbstractNavigatorFactory.groovy:43)
at geb.navigator.factory.BrowserBackedNavigatorFactory.createBase(BrowserBackedNavigatorFactory.groovy:33)
at geb.navigator.factory.BrowserBackedNavigatorFactory$_getBase_closure1.doCall(BrowserBackedNavigatorFactory.groovy:39)
at geb.waiting.Wait.waitFor(Wait.groovy:113)
... 16 more
| Completed 1 functional test, 1 failed in 10988ms 

I've been scouring through Stackoverflow, issues on geb/issues and geb/geb and going through the source code. I have no idea what is causing this issue. I can see Firefox open and navigating successfully to the login page, but alas.

Just to reiterate, once we have decent test coverage we can start upgrading all the dependencies, but for the time we have to stick with the hand we've been dealt.

Any help would be appreciated!

Thanks in advance.

-- 

Kenneth Kalmer
@kennethkalmer

Colin Harrington

unread,
Oct 6, 2015, 12:33:23 PM10/6/15
to geb-...@googlegroups.com
What does LoginPage look like? looks like the navigation to LoginPage is timing out.

LoginPage.groovy:18

Also because your test is a GebReportingTest, you can look for the screenshot and source of the page when it failed in the test-reports directory. What do you see?

~ Colin

Colin Harrington
colin.ha...@gmail.com

--
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 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/313c8a24-84df-458f-ab25-026b772d0356%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kenneth Kalmer

unread,
Oct 6, 2015, 1:30:12 PM10/6/15
to geb-...@googlegroups.com
Hi Colin

The screenshot shows the form, the HTML file has the complete markup too.

It seems to me that it is getting a handle on the element, but then somehow the geb.navigator.NonEmptyNavigator class isn't found by the JVM. I've even tried adding an import statement at the top of the test, but alas.

Anything else I can provide for better context?

Thanks for the quick response!

Kind regards

You received this message because you are subscribed to a topic in the Google Groups "Geb User Mailing List" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/geb-user/f79v-oY9OBc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to geb-user+u...@googlegroups.com.

To post to this group, send email to geb-...@googlegroups.com.

Brian Kotek

unread,
Oct 6, 2015, 3:35:43 PM10/6/15
to Geb User Mailing List
Well obviously NonEmptyNavigator is part of the Geb library, so if you're including the JAR and other Geb classes resolve, then I don't see any way that you couldn't have the class. I think something else must be going on.

Maybe try running the Grails example (https://github.com/geb/geb-example-grails) and make sure that works? 

Kenneth Kalmer

unread,
Oct 6, 2015, 5:48:16 PM10/6/15
to geb-...@googlegroups.com
Hey Brian

Example ran without a glitch. I built up my config using that repo as the primary source of inspiration.

As an aside, I just ran grails clean before rerunning the tests and it made no difference. I also had a look at an old thread [1] on the gradle forum which mentions a similar issue with geb, but no dice.

Anything else I could debug?

Thanks!


Brian Kotek

unread,
Oct 6, 2015, 6:05:02 PM10/6/15
to Geb User Mailing List
Unfortunately, no. If the example ran, then we know Geb SHOULD be working fine with Grails. Which means the problem has to be in your code or configuration somewhere. But I can't even think of what could cause the class loader to fail to find a class that we know is present in the jar.

Maybe do a global search though your own project to see if there's any code that's doing any runtime craziness or metaprogramming that would be altering things or manipulating the class loader?

(If it's not obvious, I'm totally reaching here since I really have no clue....)


Colin Harrington

unread,
Oct 6, 2015, 10:03:58 PM10/6/15
to geb-...@googlegroups.com
Kenneth, 

Based on your original stacktrace, it looks like the LoginPage.login() is waiting for an element that isn't there.  Can you share the code for LoginPage too? 

My guess is that the something in the login page isn't resolving correctly.  

LoginPage.login(LoginPage.groovy:18)or line 10

~ Colin


Colin Harrington
colin.ha...@gmail.com

Marcin Erdmann

unread,
Oct 7, 2015, 2:57:43 AM10/7/15
to geb-...@googlegroups.com
Colin, Kenneth's code indeed fails with a wait timeout from within LoginPage.login() but if you look down the stacktrace you will notice that it is caused by a NoClassDefFoundError which is the real cause of the failure.

There has to be indeed something dodgy going on with class loading there as Brian suggested because that class is part of geb-core and if geb-core wasn't on your classpath then you wouldn't even be able to navigate to pages let alone take reports which apparently works.

Kenneth, can you please:
- provide code for LoginPage as asked by Colin
- provide the full stack trace, i.e without "... 16 more" at the end
- try setting baseNavigatorWaiting to false and reporting what happens then because as far as I can see the NoClassDefFoundError is being thrown when waiting for the base navigator

P.s. Poor you, not only having to retrofit tests on a legacy project but also hitting a wall so early in the process... 

Kenneth Kalmer

unread,
Oct 7, 2015, 5:12:53 AM10/7/15
to Geb User Mailing List
Hi Brian, Collin & Marcin

Thanks for the help so far.

We nailed down the problem by downgrading to geb 0.9.1. Apart from the being completely blind to the big red warning on the grails plugin page for geb, the signal that lead us down this path was finding a hidden exception by stepping through the geb code during a debug run. We found this:

java.lang.IncompatibleClassChangeError: the number of constructors during runtime and compile time for groovy.lang.DelegatingMetaClass do not match. Expected -1 but got 2

We caught this one in Wait#waitFor, coming out the call to the passed block, but it is impossible (for me at least) to find the source since the stacktrace is empty. In my earlier search this reminded me of coming across similar exceptions where code compiled on JDK 6 wouldn't run on JDK 7, so it was a fresh starting point for the search.

For the sake of completeness, and for others that might find this thread in future, below is the current test class, page object and full stack trace when using 0.10.0.

The test as it stands now:

import geb.junit4.GebReportingTest
import org.junit.Test
import pages.LoginPage

class LoginTest extends GebReportingTest {

@Test
void testLoginFailure() {
to LoginPage

page.login("foo", "bar")

assert at(LoginPage)
assert loginMessage == "Please fill in required fields"
}
}

The page class:


package pages

import geb.Page

class LoginPage extends Page {
static url = "/login"
static at = { title == "Login" }

static content = {
username { $("input", id: "idnumber") }
password { $("input", id: "password") }
loginButton { $("input", type: "submit") }

loginMessage { $(".login_message").text() }
}

void login(String idnumber, String pass) {
username.value(idnumber)
password.value(pass)
loginButton.click()
}
}

Getting a hold of an unfiltered stacktrace was quite an issue, but here is the best I could pull out of IDEA (more verbose than CLI) - https://gist.github.com/kennethkalmer/94cbbf05f8b37f4446c4 (made a gist to save everyone from the 500+ line behemoth).

Interestingly enough, the last thing I did to complete the picture here was to follow Marcin's last instruction and set baseNavigatorWaiting to false. Lo and behold, the same exception I mentioned in the start of the email, complete with backtrace!

java.lang.IncompatibleClassChangeError: the number of constructors during runtime and compile time for groovy.lang.DelegatingMetaClass do not match. Expected -1 but got 2
at geb.navigator.AttributeAccessingMetaClass.<init>(AttributeAccessingMetaClass.groovy:24)
at geb.transform.AttributeAccessingMetaClassRegistrar.registerFor(AttributeAccessingMetaClassRegistrar.groovy:22)
at geb.navigator.NonEmptyNavigator.<clinit>(NonEmptyNavigator.groovy:42)
at geb.navigator.factory.DefaultInnerNavigatorFactory.createNavigator(DefaultInnerNavigatorFactory.groovy:39)
at geb.navigator.factory.AbstractNavigatorFactory.createFromWebElements(AbstractNavigatorFactory.groovy:43)
at geb.navigator.factory.BrowserBackedNavigatorFactory.createBase(BrowserBackedNavigatorFactory.groovy:33)
at geb.navigator.factory.BrowserBackedNavigatorFactory.getBase(BrowserBackedNavigatorFactory.groovy:39)
at geb.content.NavigableSupport.getBase(NavigableSupport.groovy:31)
at geb.content.NavigableSupport.$(NavigableSupport.groovy:111)
at geb.content.PageContentTemplateFactoryDelegate.$(PageContentTemplateFactoryDelegate.groovy:142)
at pages.LoginPage$__clinit__closure2_closure3.doCall(LoginPage.groovy:10)
at geb.content.PageContentTemplate.invokeFactory(PageContentTemplate.groovy:97)
at geb.content.PageContentTemplate$_create_closure1.doCall(PageContentTemplate.groovy:59)
at geb.content.PageContentTemplate.create(PageContentTemplate.groovy:82)
at geb.content.PageContentTemplate.get(PageContentTemplate.groovy:54)
at geb.content.PageContentSupport.getContent(PageContentSupport.groovy:43)
at geb.content.PageContentSupport.propertyMissing(PageContentSupport.groovy:59)
at geb.Page.propertyMissing(Page.groovy:77)
at pages.LoginPage.login(LoginPage.groovy:18)
at LoginTest.testLoginFailure(LoginTest.groovy:11)

I would be interested to know how this got swallowed up and how we could prevent ourselves from getting tripped up by something like this in the future.


Thanks again for the support, especially Marcin for the "poor you", gave us quite a chuckle.

Now to get the coverage up so we can get to a newer 2.x grails & geb!

Kind regards

 
On Wednesday, October 7, 2015 at 8:57:43 AM UTC+2, Marcin Erdmann wrote:
Colin, Kenneth's code indeed fails with a wait timeout from within LoginPage.login() but if you look down the stacktrace you will notice that it is caused by a NoClassDefFoundError which is the real cause of the failure.

There has to be indeed something dodgy going on with class loading there as Brian suggested because that class is part of geb-core and if geb-core wasn't on your classpath then you wouldn't even be able to navigate to pages let alone take reports which apparently works.

Kenneth, can you please:
- provide code for LoginPage as asked by Colin
- provide the full stack trace, i.e without "... 16 more" at the end
- try setting baseNavigatorWaiting to false and reporting what happens then because as far as I can see the NoClassDefFoundError is being thrown when waiting for the base navigator

P.s. Poor you, not only having to retrofit tests on a legacy project but also hitting a wall so early in the process... 

On Wednesday, 7 October 2015, Colin Harrington <> wrote:
Kenneth, 

Based on your original stacktrace, it looks like the LoginPage.login() is waiting for an element that isn't there.  Can you share the code for LoginPage too? 

My guess is that the something in the login page isn't resolving correctly.  

LoginPage.login(LoginPage.groovy:18)or line 10

~ Colin


Colin Harrington
colin.ha...@gmail.com

Marcin Erdmann

unread,
Oct 7, 2015, 8:22:31 AM10/7/15
to geb-...@googlegroups.com
Kenneth,

First of all thanks for providing responses to all of the questions we asked, it indeed might be useful for people who stumble upon this thread in the future.

Do I understand correctly that you're in an even worse place than I initially thought and have to use Java 6? Damn...

I believe that Geb has been compiled with Java 7 from around 0.9. Given that Java 6 EOL was February 2013 I think that it's fair for us to expect people to upgrade their jvm version if they want the latest version of the library.

We tried to keep Java 6 compatibility, for example by fixing https://github.com/geb/issues/issues/263. It looks like the failure in your case is caused by a core groovy class (groovy.lang.DelegatingMetaClass) so the strategy we used for 263 won't help here. I think that updating the groovy version used for 0.10.0 or the fact that you're using Groovy 2.4.5 (at least that what you said in your email, though I'm not sure if Grails 2.2.4 would even work with such a new version of Groovy; as far as I know Grails comes with groovy bundled in it so you actually might be running a completely different version than you'd think) to run your tests might be the cause why 0.9 line works for you but 0.10.0 doesn't. But in general, I don't see any value in supporting JDK6 anymore now that JDK7 is EOL.

WRT the behemoth of a stacktrace you provided: its an unfiltered one and not the full one I asked for, you can still see "... 503 more" at the end of it. Unfiltered stacktrace is of little value for us here but I'm pretty sure that if you provided the full stacktrace we would be able to see IncompatibleClassChangeError in it. So no, it doesn't get swallowed, you were just unfortunate enough for your stacktrace to be long enough for the real cause of the failure to be hidden in that last 16 frames of it...

Good luck with getting the coverage in!

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

Kenneth Kalmer

unread,
Oct 7, 2015, 10:53:03 AM10/7/15
to geb-...@googlegroups.com
Hi Marcin et al!

Answers interleaved below for better context.

On Wed, Oct 7, 2015 at 2:22 PM Marcin Erdmann <marcin....@proxerd.pl> wrote:
Kenneth,

First of all thanks for providing responses to all of the questions we asked, it indeed might be useful for people who stumble upon this thread in the future.

And thanks to you, Collin & Brian for asking well directed questions in the first place! It definitely helped me get into the Groovy-way of thinking about debugging. Being new to the ecosystem comes with a bit of a learning curve.
 
Do I understand correctly that you're in an even worse place than I initially thought and have to use Java 6? Damn...

Not entirely sure yet! Other developers on the team are also building with Java 7, but there was mentions of older JVM's lying around... Guess we'll see what the fallout is as the tests go into CI.
 
I believe that Geb has been compiled with Java 7 from around 0.9. Given that Java 6 EOL was February 2013 I think that it's fair for us to expect people to upgrade their jvm version if they want the latest version of the library.

I fully agree with this sentiment!
 
We tried to keep Java 6 compatibility, for example by fixing https://github.com/geb/issues/issues/263. It looks like the failure in your case is caused by a core groovy class (groovy.lang.DelegatingMetaClass) so the strategy we used for 263 won't help here. I think that updating the groovy version used for 0.10.0 or the fact that you're using Groovy 2.4.5 (at least that what you said in your email, though I'm not sure if Grails 2.2.4 would even work with such a new version of Groovy; as far as I know Grails comes with groovy bundled in it so you actually might be running a completely different version than you'd think) to run your tests might be the cause why 0.9 line works for you but 0.10.0 doesn't. But in general, I don't see any value in supporting JDK6 anymore now that JDK7 is EOL.

I did mention Groovy 2.4.5, but I only learned earlier today that Grails bundles Groovy, so to be safe I'll completely nuke Grails from the sdkman installation locally and check what IDEA complains about after the fact.

Again, I fully agree with the sentiment of not supporting EOL'ed runtimes. There just is no benefit to doing it, and the unintended side-effect is that users become complacent and don't upgrade... The whole pointing of a testing culture (and its tools) is to allow for good upgrade cadence, well, it is part of the whole point.
 
WRT the behemoth of a stacktrace you provided: its an unfiltered one and not the full one I asked for, you can still see "... 503 more" at the end of it. Unfiltered stacktrace is of little value for us here but I'm pretty sure that if you provided the full stacktrace we would be able to see IncompatibleClassChangeError in it. So no, it doesn't get swallowed, you were just unfortunate enough for your stacktrace to be long enough for the real cause of the failure to be hidden in that last 16 frames of it...

And here shows how new I am to the JVM invocation dance. I have no idea how to get those last 503 lines out. If I can get it out I'd gladly update the gist to have that, and to increase the context for future readers.
 
Good luck with getting the coverage in!

Thanks! Learning a lot at a rapid pace. The testing story is so similar, and yet so different to what I'm used to with Ruby, Go and Javascript. I'm looking forward to the technical and cultural challenges of our mission.

I have to add that I feel very confident about the contributors we have in this corner of the ring. This first interaction with the community made all the difference to me!

I hope that in time I can also make a good contribution here, in one form or another.

All the best!

Marcin Erdmann

unread,
Oct 8, 2015, 2:41:34 AM10/8/15
to geb-...@googlegroups.com
On Wednesday, 7 October 2015, Kenneth Kalmer <kenneth...@gmail.com> wrote:
And here shows how new I am to the JVM invocation dance. I have no idea how to get those last 503 lines out. If I can get it out I'd gladly update the gist to have that, and to increase the context for future readers.

If that's the case then kudos on providig the unfiltered exception, it would probably take me some significant googl ig to figure iut how to do it. Anyway, I did some googling and it turns out that "... X more" at the end of a stacktrace means that the last X frames of the exceptions are the same as the last X frames of the exceptions it caused. So basically you need to look up, find the closest "Caused by" and take the X frames above it.

This means that I was wrong and the IncompatibleClassChangeError has been indeed swallowed as you suggested. On the other hand I'm not sure if we can do much about it given that there are some serious errors thrown from bowels of groovy in this case and how all that is handled is probably out of our control. waitFor() catches the exceptions thrown from within the block and attaches them as is as the cause of WaitTimeoutException. On the other hand, implicit asertions are applied to these blocks and maybe the fact that there is an AST transformation in play here causes the stacktrace to not contain IncompatibleClassChangeError.

Anyway, we solved the issue so it's probably not worth to delve into that too much.
 
I have to add that I feel very confident about the contributors we have in this corner of the ring. This first interaction with the community made all the difference to me!

Nice to read that.

 

I hope that in time I can also make a good contribution here, in one form or another.

Looking forward to it.
Reply all
Reply to author
Forward
0 new messages