My code works fine and the WebDriver BiDi protocol is functioning correctly with the local ChromeDriver instance. But when I use a RemoteWebDriver instance connected to a Selenium Grid/Server, I get error - "java.lang.IllegalArgumentException: WebDriver instance must support BiDi protocol".
Can anyone from the selenium BiDi community help here.
Tried creating a basic test that constructs ChromeDriver with webSocketUrl capability and test if I can instantiate [JSFatalCatch] utility class and successfully initialize [LogInspector]. When I ran the below test locally, I was able to SUCCESSFULLY have WebDriver instance support BiDi protocol and initialize LogInspector.
import com.qa.test.ui.jsFatalCatch.JSFatalCatch;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.Assert;
public class BiDiLoggingTest {
public static void main(String[] args) throws Exception {
//Setup
ChromeOptions options = new ChromeOptions();
options.setCapability("webSocketUrl", true);
ChromeDriver driver = new ChromeDriver(options);
JSFatalCatch jsFatalCatch = new JSFatalCatch(driver);
driver.get("http://ccui-beta.integ.amazon.com/jsErrorOnElementAction");
driver.findElement(By.id("jsException")).click();
jsFatalCatch.addJSLogsAndExceptions();
String displayText = jsFatalCatch.getJSExceptionDisplayText();
Assert.assertTrue(displayText.contains("Error"), "JS exception found must contain expected logEntry text");
Assert.assertTrue(displayText.contains("javascript"), "JS exception found must contain expected logEntry type");
System.out.println(displayText);
System.out.println(" I HAVE PASSED!!");
driver.quit();
}
}
import com.qa.test.ui.element.Element;
import com.qa.test.ui.session.Session;
import lombok.Getter;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.LogInspector;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
// Utility Class for JSFatalCatch feature.
public class JSFatalCatch {
@Getter
private final WebDriver driver;
private final LogInspector logInspector; //This is provided by WebDriver BiDi API to inspect and capture various types of logs, including JavaScript logs, from the browser.
private CompletableFuture<JavascriptLogEntry> future; //This is to handle the asynchronous nature of capturing JavaScript log entries
private JavascriptLogEntry logEntry;
public JSFatalCatch(WebDriver driver) {
this.driver = driver;
this.logInspector = new LogInspector(driver);
this.future = new CompletableFuture<>();
//This sets up an asynchronous callback mechanism with the LogInspector instance to capture the JavaScript log entry when it becomes available.
logInspector.onJavaScriptLog(future::complete);
}
/**
* Verify if jsFatalCatch config is enabled both at the Session and respective Element level.
* JSFatalCatch feature will only be activated to check JS Errors on Browser events for UI tests if it is enabled both at Session and Element level.
*/
public boolean isJSFatalCatchEnabled(Element element) {
boolean jsFatalCatchEnabled = Session.getSession().getSessionConfig().isJsFatalCatchEnabledForSession();
if(jsFatalCatchEnabled) {
if(element.isJsFatalCatchEnabledForElement() == false) {
jsFatalCatchEnabled = element.isJsFatalCatchEnabledForElement();
}
}
return jsFatalCatchEnabled;
}
//Add JavaScript logs and exceptions that occur for the browser Session.
public void addJSLogsAndExceptions() throws Exception {
//This waits for up to 5 seconds for the CompletableFuture object to complete, i.e., for a JavaScript log entry to be captured.
logEntry = future.get(5, TimeUnit.SECONDS);
}
//Verify if any JSException occurs for browser events.
public boolean isJSExceptionPresent() throws Exception {
addJSLogsAndExceptions();
if(logEntry.getLevel() != null) {
return true;
}
return false;
}
//Returns a custom message for JSExceptions for logging purpose.
public String getJSExceptionDisplayText() throws Exception {
if(isJSExceptionPresent()) {
//Append JSException's text, level and type.
StringBuilder displayText = new StringBuilder();
displayText.append("JSException text- ");
displayText.append(logEntry.getText());
displayText.append(", JSException Level- ");
displayText.append(logEntry.getLevel());
displayText.append(" and JSException Type- ");
displayText.append(logEntry.getType());
return displayText.toString();
}
return "No JS Exceptions were logged!";
}
}
Investigation notes :
CASE 1 : When I use [Local ChromeDriver instance] the [driver] and [jsFatalCatch] objects in BiDiLoggingTest class work successfully.
Driver : (Captured putting debug points)
Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 122.0.6261.112, chrome: {chromedriverVersion: 122.0.6261.94 (880dbf29479c..., userDataDir: /var/folders/lw/n7ymtq912_n...}, fedcm:accounts: true, goog:chromeOptions: {debuggerAddress: localhost:60015}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: mac, proxy: Proxy(), se:cdp: ws://localhost:60015/devtoo..., se:cdpVersion: 122.0.6261.112, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webSocketUrl: ws://localhost:9111/session..., webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:extension:minPinLength: true, webauthn:extension:prf: true, webauthn:virtualAuthenticators: true} biDiUri : Optional[ws://localhost:9111/session/7cf7dac1edd6bd93565cd79d5bca75b9] biDi : Optional[org.openqa.selenium.bidi.BiDi@1cd201a8] RemoteWebdriver.capabilities : Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 122.0.6261.112, chrome: {chromedriverVersion: 122.0.6261.94 (880dbf29479c..., userDataDir: /var/folders/lw/n7ymtq912_n...}, fedcm:accounts: true, goog:chromeOptions: {debuggerAddress: localhost:60015}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: mac, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webSocketUrl: ws://localhost:9111/session..., webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:extension:minPinLength: true, webauthn:extension:prf: true, webauthn:virtualAuthenticators: true} So based on the above, I have these 2 values under my Driver:
biDiUri : Optional[ws://localhost:9111/session/7cf7dac1edd6bd93565cd79d5bca75b9]- This is the WebSocket URL that is being used for the WebDriver BiDi connection. It's a WebSocket connection to the specified host and port, with a unique session ID.
biDi : Optional[org.openqa.selenium.bidi.BiDi@1cd201a8] - This is the instance of the BiDi class, which is part of the WebDriver BiDi API. This class is used to interact with the browser's debugging protocol and send commands.
The presence of the biDiUri and biDi entries in the debug console indicates that the WebDriver BiDi connection has been successfully established. This is a prerequisite for using the LogInspector and other WebDriver BiDi APIs to interact with the browser's logging and debugging features.
Conclusion : Since the WebDriver BiDi protocol is functioning correctly with the local ChromeDriver instance, it rules out any issues with my code or the implementation of the LogInspector and JSFatalCatch classes. This suggests that the problem lies specifically with the Selenium Server (Grid) setup.
CASE 2 : When I use [RemoteWebDriver instance connected to a Selenium Grid/Server] I get the error "java.lang.IllegalArgumentException: WebDriver instance must support BiDi protocol" indicating that the WebDriver instance I am using in this test case does not support the WebDriver BiDi protocol.
Driver : (Captured putting debug points)
Capabilities {acceptInsecureCerts: true, browserName: chrome, browserVersion: 122.0.6261.112, chrome: {chromedriverVersion: 122.0.6261.94 (880dbf29479c..., userDataDir: /var/folders/lw/n7ymtq912_n...}, fedcm:accounts: true, goog:chromeOptions: {debuggerAddress: localhost:61474}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: mac, proxy: Proxy(), se:bidi: ws://10.0.0.79:4444/session..., se:cdp: ws://10.0.0.79:4444/session..., se:cdpVersion: 122.0.6261.112, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webSocketUrl: ws://localhost:28501/sessio..., webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:extension:minPinLength: true, webauthn:extension:prf: true, webauthn:virtualAuthenticators: true}