I am getting an error when using a LogEventListener.
When I just print something, for example in the beforeEvent method, everything is fine, but when I set any action in any method, I get this error:
java.lang.StackOverflowError
at java.base/java.lang.String.replace(String.java:2173)
at com.codeborne.selenide.impl.SelenideElementDescriber.selector(SelenideElementDescriber.java:67)
at com.codeborne.selenide.impl.ElementFinder.elementCriteria(ElementFinder.java:137)
at com.codeborne.selenide.impl.ElementFinder.getSearchCriteria(ElementFinder.java:130)
at com.codeborne.selenide.impl.Alias$NoneAlias.getOrElse(Alias.java:43)
at com.codeborne.selenide.impl.WebElementSource.description(WebElementSource.java:60)
at com.codeborne.selenide.impl.SelenideElementProxy.invoke(SelenideElementProxy.java:81)
at jdk.proxy2/jdk.proxy2.$Proxy17.is(Unknown Source)
at com.bme.listeners.EventLogger.beforeEvent(EventLogger.java:16)
at com.codeborne.selenide.logevents.SelenideLogger.beginStep(SelenideLogger.java:121)
at com.codeborne.selenide.logevents.SelenideLogger.beginStep(SelenideLogger.java:57)
at com.codeborne.selenide.impl.SelenideElementProxy.invoke(SelenideElementProxy.java:81)**
Code:
public class EventLogger implements LogEventListener {
@Override
public void beforeEvent(LogEvent log) {
if(Selenide.$("path").is(visible)) {
System.out.println("Before Event");
}
}
@Override
public void afterEvent(LogEvent log) {
}
}
Can anyone help me understand?
My best guess as to the cause of this problem is that calling Selenide.$("path").is(visible)
causes a log event to be generated. This would cause your listener gets called again, so Selenide.$("path").is(visible)
gets called again, which causes another log event, so your listener gets called again, and so on and so on until the stack overflows. However, I don't have enough of your stacktrace to be sure. I would be more sure of this problem if you could include the stacktrace down as far as the second line in which com.bme.listeners.EventLogger.beforeEvent
appears.
What might help is adding a boolean field to your listener that records whether it is currently logging an event, and does nothing if beforeEvent
is called and this field is true
:
public class EventLogger implements LogEventListener {
private boolean isCurrentlyLoggingAnEvent = false;
@Override
public void beforeEvent(LogEvent log) {
if (isCurrentlyLoggingAnEvent) {
// Prevent recursive call.
return;
}
isCurrentlyLoggingAnEvent = true;
try {
if(Selenide.$("path").is(visible)) {
System.out.println("Before Event");
}
}
finally {
isCurrentlyLoggingAnEvent = false;
}
}
@Override
public void afterEvent(LogEvent log) {
}
}
I've used a try
-finally
block to ensure that the field isCurrentlyLoggingAnEvent
is always set back to false
, even when an exception is thrown from within the try
block.
If you plan to put any logic in afterEvent
, you may want to consider doing something similar there.