Chrome DevTools Protocol version 99 support library for Selenium WebDriver Java bindings
—
Browser event monitoring including console messages, JavaScript exceptions, and runtime events for debugging and monitoring. Provides comprehensive access to browser-side events for testing and debugging purposes.
import org.openqa.selenium.devtools.v99.V99Events;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.Command;
import org.openqa.selenium.devtools.Event;
import org.openqa.selenium.devtools.events.ConsoleEvent;
import org.openqa.selenium.JavascriptException;
import java.util.function.Consumer;Creates an event monitoring handler for Chrome DevTools Protocol v99.
/**
* Creates event monitoring handler for CDP v99
* @param devtools - DevTools client instance
*/
public V99Events(DevTools devtools);Enable and disable the JavaScript runtime domain for event collection.
/**
* Enable JavaScript runtime domain for event monitoring
* @return Command to enable runtime
*/
protected Command<Void> enableRuntime();
/**
* Disable JavaScript runtime domain
* @return Command to disable runtime
*/
protected Command<Void> disableRuntime();Convenient methods for adding event listeners with automatic event conversion.
/**
* Add listener for console events (console.log, console.error, etc.)
* @param listener - Consumer that receives console events
*/
public void addConsoleListener(Consumer<ConsoleEvent> listener);
/**
* Add listener for JavaScript exceptions
* @param listener - Consumer that receives JavaScript exception events
*/
public void addJavascriptExceptionListener(Consumer<JavascriptException> listener);
/**
* Disable event monitoring and clean up listeners
*/
public void disable();Monitor browser console API calls (console.log, console.error, etc.).
/**
* Get event handler for console API calls
* @return Event for console messages
*/
protected Event<ConsoleAPICalled> consoleEvent();
/**
* Convert CDP console event to Selenium console event
* @param event - CDP console API called event
* @return Selenium console event
*/
protected ConsoleEvent toConsoleEvent(ConsoleAPICalled event);Monitor JavaScript exceptions thrown in the browser.
/**
* Get event handler for JavaScript exceptions
* @return Event for JavaScript exceptions
*/
protected Event<ExceptionThrown> exceptionThrownEvent();
/**
* Convert CDP exception event to JavaScript exception
* @param event - CDP exception thrown event
* @return JavascriptException with stack trace
*/
protected JavascriptException toJsException(ExceptionThrown event);/**
* Console API called event from CDP
*/
public class ConsoleAPICalled {
/**
* Get console call type (log, error, warn, etc.)
* @return Console API type
*/
public ConsoleAPIType getType();
/**
* Get console message arguments
* @return List of remote objects representing arguments
*/
public List<RemoteObject> getArgs();
/**
* Get timestamp of console call
* @return Timestamp
*/
public Timestamp getTimestamp();
/**
* Get execution context ID where console was called
* @return Context ID
*/
public ExecutionContextId getExecutionContextId();
/**
* Get stack trace if available
* @return Optional stack trace
*/
public Optional<StackTrace> getStackTrace();
}
/**
* Console API call types
*/
public enum ConsoleAPIType {
LOG("log"),
DEBUG("debug"),
INFO("info"),
ERROR("error"),
WARNING("warning"),
CLEAR("clear"),
DIR("dir"),
DIRXML("dirxml"),
TABLE("table"),
TRACE("trace"),
STARTGROUP("startGroup"),
STARTGROUPCOLLAPSED("startGroupCollapsed"),
ENDGROUP("endGroup"),
ASSERT("assert"),
PROFILE("profile"),
PROFILEEND("profileEnd"),
COUNT("count"),
TIMEEND("timeEnd");
}
/**
* Selenium console event (converted from CDP)
*/
public class ConsoleEvent {
public ConsoleEvent(String type, Instant timestamp, List<Object> messages);
public String getType();
public Instant getTimestamp();
public List<Object> getMessages();
}/**
* JavaScript exception thrown event from CDP
*/
public class ExceptionThrown {
/**
* Get exception details
* @return Exception details
*/
public ExceptionDetails getExceptionDetails();
/**
* Get timestamp when exception occurred
* @return Timestamp
*/
public Timestamp getTimestamp();
}
/**
* Detailed exception information
*/
public class ExceptionDetails {
/**
* Get exception ID
* @return Exception ID
*/
public ExceptionId getExceptionId();
/**
* Get exception text/message
* @return Exception message
*/
public String getText();
/**
* Get line number where exception occurred
* @return Line number
*/
public Integer getLineNumber();
/**
* Get column number where exception occurred
* @return Column number
*/
public Integer getColumnNumber();
/**
* Get URL/script where exception occurred
* @return Optional URL
*/
public Optional<String> getUrl();
/**
* Get stack trace if available
* @return Optional stack trace
*/
public Optional<StackTrace> getStackTrace();
/**
* Get exception object details
* @return Optional remote object representing the exception
*/
public Optional<RemoteObject> getException();
/**
* Get execution context ID where exception occurred
* @return Optional context ID
*/
public Optional<ExecutionContextId> getExecutionContextId();
}/**
* Remote JavaScript object representation
*/
public class RemoteObject {
/**
* Get object type (string, number, boolean, object, etc.)
* @return Object type
*/
public RemoteObjectType getType();
/**
* Get object value if primitive
* @return Optional value
*/
public Optional<Object> getValue();
/**
* Get object description
* @return Optional description string
*/
public Optional<String> getDescription();
}
/**
* JavaScript stack trace information
*/
public class StackTrace {
/**
* Get description of the stack trace
* @return Optional description
*/
public Optional<String> getDescription();
/**
* Get call frames in the stack trace
* @return List of call frames
*/
public List<CallFrame> getCallFrames();
/**
* Get parent stack trace if available
* @return Optional parent stack trace
*/
public Optional<StackTrace> getParent();
}
/**
* Individual call frame in stack trace
*/
public class CallFrame {
/**
* Get function name
* @return Function name
*/
public String getFunctionName();
/**
* Get script URL
* @return Script URL
*/
public String getUrl();
/**
* Get line number in script
* @return Line number (0-based)
*/
public Integer getLineNumber();
/**
* Get column number in line
* @return Column number (0-based)
*/
public Integer getColumnNumber();
}
/**
* CDP timestamp representation
*/
public class Timestamp {
/**
* Convert timestamp to JSON number
* @return JSON representation
*/
public JsonInput toJson();
/**
* Convert to string representation
* @return String representation
*/
public String toString();
}import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v99.V99Domains;
import org.openqa.selenium.devtools.events.ConsoleEvent;
DevTools devTools = ...; // from ChromeDriver
V99Domains domains = new V99Domains(devTools);
// Add console listener using high-level API
domains.events().addConsoleListener(consoleEvent -> {
System.out.printf("[%s] %s: %s%n",
consoleEvent.getTimestamp(),
consoleEvent.getType(),
consoleEvent.getMessages()
);
});
// Now navigate to page - console messages will be captured
driver.get("https://example.com");// Add JavaScript exception listener using high-level API
domains.events().addJavascriptExceptionListener(jsException -> {
System.err.println("JavaScript Exception: " + jsException.getMessage());
// Print stack trace
for (StackTraceElement element : jsException.getStackTrace()) {
System.err.println(" at " + element.toString());
}
});
// This will trigger exception monitoring for any JavaScript errors
driver.executeScript("throw new Error('Test exception');");// Set up both console and exception monitoring together
domains.events().addConsoleListener(consoleEvent -> {
// Handle console messages based on type
switch (consoleEvent.getType()) {
case "error":
System.err.println("Console Error: " + consoleEvent.getMessages());
break;
case "warning":
System.out.println("Console Warning: " + consoleEvent.getMessages());
break;
default:
System.out.println("Console " + consoleEvent.getType() + ": " + consoleEvent.getMessages());
}
});
domains.events().addJavascriptExceptionListener(jsException -> {
System.err.println("JavaScript Exception: " + jsException.getMessage());
logExceptionToTestResults(jsException);
});
// Execute test operations - both console and exception events will be captured
// Cleanup when done
domains.events().disable(); // Disables runtime and cleans up listenersdevTools.send(domains.events().enableRuntime());
devTools.addListener(domains.events().consoleEvent(), consoleApiEvent -> {
String type = consoleApiEvent.getType().toString();
List<RemoteObject> args = consoleApiEvent.getArgs();
// Process different console types differently
switch (type) {
case "error":
handleConsoleError(args);
break;
case "warning":
handleConsoleWarning(args);
break;
case "log":
case "info":
handleConsoleInfo(args);
break;
case "table":
handleConsoleTable(args);
break;
default:
handleGenericConsole(type, args);
}
});
private void handleConsoleError(List<RemoteObject> args) {
// Convert remote objects to meaningful error data
args.forEach(arg -> {
if (arg.getType() == RemoteObjectType.STRING && arg.getValue().isPresent()) {
System.err.println("Console Error: " + arg.getValue().get());
}
});
}// Store execution contexts for filtering
Set<ExecutionContextId> monitoredContexts = new HashSet<>();
devTools.addListener(domains.events().consoleEvent(), consoleEvent -> {
ExecutionContextId contextId = consoleEvent.getExecutionContextId();
// Only process events from specific contexts
if (monitoredContexts.contains(contextId)) {
ConsoleEvent seleniumEvent = domains.events().toConsoleEvent(consoleEvent);
processConsoleEvent(seleniumEvent);
}
});
// Add context to monitoring set when needed
// (typically done through other DevTools events or direct context creation)devTools.addListener(domains.events().exceptionThrownEvent(), exceptionEvent -> {
ExceptionDetails details = exceptionEvent.getExceptionDetails();
System.err.println("Exception Details:");
System.err.println(" Message: " + details.getText());
System.err.println(" Line: " + details.getLineNumber());
System.err.println(" Column: " + details.getColumnNumber());
details.getUrl().ifPresent(url ->
System.err.println(" URL: " + url));
details.getStackTrace().ifPresent(stackTrace -> {
System.err.println(" Stack Trace:");
stackTrace.getCallFrames().forEach(frame -> {
System.err.printf(" at %s (%s:%d:%d)%n",
frame.getFunctionName().isEmpty() ? "<anonymous>" : frame.getFunctionName(),
frame.getUrl(),
frame.getLineNumber(),
frame.getColumnNumber()
);
});
});
});// Always disable runtime when done to clean up resources
try {
// Perform operations requiring event monitoring
performTestOperations();
} finally {
// Clean up - disable runtime domain
devTools.send(domains.events().disableRuntime());
}Event monitoring operations can encounter various issues:
Handle errors through proper exception handling and resource management:
try {
devTools.send(domains.events().enableRuntime());
// Set up event listeners
setupEventListeners();
// Perform test operations
runTests();
} catch (DevToolsException e) {
System.err.println("Failed to enable event monitoring: " + e.getMessage());
} finally {
// Always clean up
try {
devTools.send(domains.events().disableRuntime());
} catch (Exception e) {
System.err.println("Failed to disable runtime: " + e.getMessage());
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-seleniumhq-selenium--selenium-devtools-v99