Skip to main content
No Result Found

Learn about event-driven testing with Selenium BiDi

Learn how to optimize your test scripts to use Selenium 4 event-driven testing with BrowserStack Automate.

Initially, CDP was a temporary solution for advanced browser automation until browser vendors could develop a more comprehensive cross-browser protocol.

CDP supports only Chromium-based browsers. Its implementation in Firefox has been incomplete and is expected to be deprecated. This limitation highlighted the need for a standardized protocol to enhance automation across different browsers.

Enter the WebDriver BiDi Protocol, a next-generation protocol developed under the W3C. Designed for enhanced browser automation, the WebDriver BiDi Protocol is set to become the standard for automated testing across various browsers.

Selenium now supports the W3C WebDriver BiDi Protocol.

Key Features of WebDriver BiDi Protocol

Selenium BiDi offers the following benefits:

  • Cross-Browser Compatibility: Unlike CDP, which is limited to Chromium-based browsers, the WebDriver BiDi Protocol is designed to work seamlessly across different browsers, including Firefox.
  • Event-Driven Automation: Enables testing scripts to react to browser events as they happen, improving the efficiency and effectiveness of test automation.
  • Standardization: As a W3C standard, the WebDriver BiDi Protocol ensures consistency and interoperability across various browser implementations.
  • Future-Proofing: Major browser vendors are committed to supporting the WebDriver BiDi Protocol, which represents the future of browser automation testing.

You can start your event-driven testing journey with the following features available in Selenium’s BiDi:

To perform event-driven tests, use the seleniumBidi capability in your test script to perform event-driven tests.

Capability Description Expected values
seleniumBidi Enables the Selenium’s BiDi features in a test script. Boolean.
Set to true if you plan to use BiDi features. Accepted values are true and false. Default is false.
This sets webSocketUrl to true for the browser, so that the user does not have to set it explicitly as required by Selenium.

Currently, all the feature implementation sample code snippets are available only in Java and Javascript in Selenium. We plan to add code snippets for other languages soon.

There are certain features of BiDi that are not supported by the browsers yet. This may result in an error when running your builds. The following table highlights a few examples of features that the browsers do not support:

Browser Latest Version Latest-1 Version
Chrome 125 124
Edge 125 124
Firefox 126 125

You can check out the W3C BiDi progress of the browsers. Click the EDIT link to select your preferred browser and version.

Listen to console.log events

Console logs are generally used to uncover the cause of a bug in the code execution. Use this API to listen to the console.log events and register callbacks to process the event for displaying the logs.

The following test script navigates to a web page and clicks a button that generates console logs. This triggers an event with all the log details.

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;


public class ListenToConsoleLogs {
   public static String REMOTE_URL = "https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub";
   static Boolean success = false;


   public static void main(String[] args) throws MalformedURLException {
       MutableCapabilities capabilities = new MutableCapabilities();
       capabilities.setCapability("browserName", "chrome");
       HashMap<String, Object> browserstackOptions = new HashMap<>();
       browserstackOptions.put("os", "OS X");
       browserstackOptions.put("osVersion", "Big Sur");
       browserstackOptions.put("sessionName", "Console Logs");
       browserstackOptions.put("seleniumVersion", "4.20.0");
       // This can be replaced with the appropriate flag
       browserstackOptions.put("seleniumBidi", true);
       capabilities.setCapability("bstack:options", browserstackOptions);


       WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities);


       try {
           Augmenter augmenter = new Augmenter();
           driver = augmenter.augment(driver);




           try (LogInspector logInspector = new LogInspector(driver)) {
               logInspector.onConsoleEntry(consoleLogEntry -> {
                   System.out.println("text: " + consoleLogEntry.getText());
                   System.out.println("level: " + consoleLogEntry.getLevel());
                   success = true;
               });


               String page = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";
               driver.get(page);
               driver.findElement(By.id("consoleLog")).click();


  
               if (success) {
                   markTestStatus("passed", "Console logs streaming", driver);
               } else {
                   markTestStatus("failed", "Console logs did not stream", driver);
               }
               driver.quit();
           }


       } catch (Exception e) {
           markTestStatus("failed", "Exception!", driver);
           e.printStackTrace();
           driver.quit();
       }
   }


   public static void markTestStatus(String status, String reason, WebDriver driver) {
       JavascriptExecutor jse = (JavascriptExecutor) driver;
       jse.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"" + status + "\", \"reason\": \"" + reason + "\"}}");
   }
}
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

def console_log():
    desired_cap = {
        'name': 'Bstack-[Python] Sample Test',
        'seleniumBidi': 'true',
        'seleniumVersion': '4.20.0'
    }

    options = webdriver.ChromeOptions()
    options.set_capability('bstack:options', desired_cap)
    options.enable_bidi = True

    driver = webdriver.Remote(
        command_executor='https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub', options=options)

    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    driver.script.add_console_message_handler(log_entries.append)

    driver.find_element(By.ID, "consoleLog").click()
    WebDriverWait(driver, 5).until(lambda _: log_entries)
    print(log_entries[0].text)
    driver.quit()

Listen to JavaScript Exceptions

Exception, as commonly known, is an unusual event that breaks the normal execution flow of a program.

Use this API to listen to the JavaScript exceptions and register callbacks to process the exception details. These exception details can assist in further inspecting the cause and aiding the debugging process.

The following test script navigates to a web page and clicks a button that throws an error. This fires an event with all the error details.

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.RemoteWebDriver;


import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;


public class ListenToJavaScriptExceptions {
   public static String REMOTE_URL = "https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub";
   static Boolean success = false;


   public static void main(String[] args) throws MalformedURLException {
       MutableCapabilities capabilities = new MutableCapabilities();
       capabilities.setCapability("browserName", "chrome");
       HashMap<String, Object> browserstackOptions = new HashMap<>();
       browserstackOptions.put("os", "OS X");
       browserstackOptions.put("osVersion", "Big Sur");
       browserstackOptions.put("sessionName", "Console Logs");
       browserstackOptions.put("seleniumVersion", "4.20.0");
       // This can be replaced with the appropriate flag
       browserstackOptions.put("seleniumBidi", true);
       capabilities.setCapability("bstack:options", browserstackOptions);


       WebDriver driver = new RemoteWebDriver(new URL(REMOTE_URL), capabilities);


       try {
           Augmenter augmenter = new Augmenter();
           driver = augmenter.augment(driver);


           try (LogInspector logInspector = new LogInspector(driver)) {
               logInspector.onJavaScriptException(logEntry -> {
                   System.out.println("text: " + logEntry.getText());
                   System.out.println("level: " + logEntry.getLevel());
                   success = true;
               });


               String page = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";
               driver.get(page);
               driver.findElement(By.id("jsException")).click();


               Thread.sleep(1000);
               if (success) {
                   markTestStatus("passed", "Js exception caught", driver);
               } else {
                   markTestStatus("failed", "Js exception was not caught", driver);
               }
               driver.quit();
           }


       } catch (Exception e) {
           markTestStatus("failed", "Exception!", driver);
           e.printStackTrace();
           driver.quit();
       }
   }


   public static void markTestStatus(String status, String reason, WebDriver driver) {
       JavascriptExecutor jse = (JavascriptExecutor) driver;
       jse.executeScript("browserstack_executor: {\"action\": \"setSessionStatus\", \"arguments\": {\"status\": \"" + status + "\", \"reason\": \"" + reason + "\"}}");
   }
}

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait

def js_exception():
    desired_cap = {
        'name': 'Bstack-[Python] Sample Test',
        'seleniumBidi': 'true',
        'seleniumVersion': '4.20.0'
    }

    options = webdriver.ChromeOptions()
    options.set_capability('bstack:options', desired_cap)
    options.enable_bidi = True

    driver = webdriver.Remote(
        command_executor='https://YOUR_USERNAME:YOUR_ACCESS_KEY@hub-cloud.browserstack.com/wd/hub', options=options)

    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    driver.script.add_javascript_error_handler(log_entries.append)

    driver.find_element(By.ID, "jsException").click()
    WebDriverWait(driver, 5).until(lambda _: log_entries)
    print(log_entries[0].text)
    driver.quit()

Intercept Network Request

Intercepting network requests allows for inspection and modification of the outgoing requests. This can be used to monitor network traffic or mock outgoing requests by modifying the headers, body, cookies, method, and/or URL.

Copy icon Copy

Intercept Network Response

Intercepting network responses allows for inspection and modification of the incoming responses. This can be used to monitor network traffic or mock responses by modifying the headers, cookies, credentials, reason phrases, and/or status codes.

Copy icon Copy

Register Basic Auth

Some websites use the browser authentication method to secure web pages. Using Selenium, you can write an automated test script that enters your credentials in the basic auth popup window whenever it appears.

The following test script opens a website and enters sample credentials in the basic auth popup window:

Copy icon Copy

Conclusion

The W3C BiDi protocol is currently under development and being implemented by browser vendors. Selenium is keeping pace and aims to fully implement the BiDi protocol, providing user-friendly APIs for common use cases in future versions.

Currently, the Java and JavaScript BiDi APIs align with the W3C BiDi specification, even if some features are only available in beta versions of browsers. Python and Ruby have the initial BiDi support in form of high-level APIs.

For browser status updates, check here. Find more examples and version support in Selenium here.

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback

Is this page helping you?

Yes
No

We're sorry to hear that. Please share your feedback so we can do better

Contact our Support team for immediate help while we work on improving our docs.

We're continuously improving our docs. We'd love to know what you liked





Thank you for your valuable feedback!

Talk to an Expert
Download Copy Check Circle