これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.

このページの通常のビューに戻る.

双方向機能

BiDirectional means that communication is happening in two directions simultaneously. The traditional WebDriver model involves strict request/response commands which only allows for communication to happen in one direction at any given time. In most cases this is what you want; it ensures that the browser is doing the expected things in the right order, but there are a number of interesting things that can be done with asynchronous interactions.

This functionality is currently available in a limited fashion with the [Chrome DevTools Protocol] (CDP), but to address some of its drawbacks, the Selenium team, along with the major browser vendors, have worked to create the new WebDriver BiDi Protocol. This specification aims to create a stable, cross-browser API that leverages bidirectional communication for enhanced browser automation and testing functionality, including streaming events from the user agent to the controlling software via WebSockets. Users will be able to listen for and record or manipulate events as they happen during the course of a Selenium session.

Enabling BiDi in Selenium

In order to use WebDriver BiDi, setting the capability in the browser options will enable the required functionality:

options.setCapability("webSocketUrl", true);
options.enable_bidi = True
UseWebSocketUrl = true,
options.web_socket_url = true
Options().enableBidi();
options.setCapability("webSocketUrl", true);

This enables the WebSocket connection for bidirectional communication, unlocking the full potential of the WebDriver BiDi protocol.

Note that Selenium is updating its entire implementation from WebDriver Classic to WebDriver BiDi (while maintaining backwards compatibility as much as possible), but this section of documentation focuses on the new functionality that bidirectional communication allows. The low-level BiDi domains will be accessible in the code to the end user, but the goal is to provide high-level APIs that are straightforward methods of real-world use cases. As such, the low-level components will not be documented, and this section will focus only on the user-friendly features that we encourage users to take advantage of.

If there is additional functionality you’d like to see, please raise a feature request.

1 - WebDriver BiDi Logging Features

These features are related to logging. Because “logging” can refer to so many different things, these methods are made available via a “script” namespace.

Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi

Console Message Handlers

Record or take actions on console.log events.

Add Handler

    driver.script.add_console_message_handler(log_entries.append)
Show full example
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
    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)
    assert log_entries[0].text == "Hello, world!"


@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_console_message_handler(log_entries.append)
    driver.script.remove_console_message_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0


@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
    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)
    assert log_entries[0].text == "Error: Not working"


@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_javascript_error_handler(log_entries.append)
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0
    log_entries = []
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_bidi_session }
  let(:wait) { Selenium::WebDriver::Wait.new(timeout: 2) }

  it 'adds console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_console_message_handler { |log| log_entries << log }

    driver.find_element(id: 'consoleLog').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Hello, world!'
  end

  it 'removes console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_console_message_handler { |log| log_entries << log }
    driver.script.remove_console_message_handler(id)

    driver.find_element(id: 'consoleLog').click
    expect(log_entries).to be_empty
  end

  it 'adds JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_javascript_error_handler { |error| log_entries << error }

    driver.find_element(id: 'jsException').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Error: Not working'
  end

  it 'removes JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_javascript_error_handler { |error| log_entries << error }
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(id: 'jsException').click
    expect(log_entries).to be_empty
  end
end

Remove Handler

You need to store the ID returned when adding the handler to delete it.

    id = driver.script.add_console_message_handler(log_entries.append)
    driver.script.remove_console_message_handler(id)
Show full example
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
    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)
    assert log_entries[0].text == "Hello, world!"


@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_console_message_handler(log_entries.append)
    driver.script.remove_console_message_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0


@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
    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)
    assert log_entries[0].text == "Error: Not working"


@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_javascript_error_handler(log_entries.append)
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0
    log_entries = []
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_bidi_session }
  let(:wait) { Selenium::WebDriver::Wait.new(timeout: 2) }

  it 'adds console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_console_message_handler { |log| log_entries << log }

    driver.find_element(id: 'consoleLog').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Hello, world!'
  end

  it 'removes console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_console_message_handler { |log| log_entries << log }
    driver.script.remove_console_message_handler(id)

    driver.find_element(id: 'consoleLog').click
    expect(log_entries).to be_empty
  end

  it 'adds JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_javascript_error_handler { |error| log_entries << error }

    driver.find_element(id: 'jsException').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Error: Not working'
  end

  it 'removes JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_javascript_error_handler { |error| log_entries << error }
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(id: 'jsException').click
    expect(log_entries).to be_empty
  end
end

JavaScript Exception Handlers

Record or take actions on JavaScript exception events.

Add Handler

    driver.script.add_javascript_error_handler(log_entries.append)
Show full example
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
    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)
    assert log_entries[0].text == "Hello, world!"


@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_console_message_handler(log_entries.append)
    driver.script.remove_console_message_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0


@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
    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)
    assert log_entries[0].text == "Error: Not working"


@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_javascript_error_handler(log_entries.append)
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0
    log_entries = []
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_bidi_session }
  let(:wait) { Selenium::WebDriver::Wait.new(timeout: 2) }

  it 'adds console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_console_message_handler { |log| log_entries << log }

    driver.find_element(id: 'consoleLog').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Hello, world!'
  end

  it 'removes console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_console_message_handler { |log| log_entries << log }
    driver.script.remove_console_message_handler(id)

    driver.find_element(id: 'consoleLog').click
    expect(log_entries).to be_empty
  end

  it 'adds JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_javascript_error_handler { |error| log_entries << error }

    driver.find_element(id: 'jsException').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Error: Not working'
  end

  it 'removes JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_javascript_error_handler { |error| log_entries << error }
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(id: 'jsException').click
    expect(log_entries).to be_empty
  end
end

Remove Handler

You need to store the ID returned when adding the handler to delete it.

    id = driver.script.add_javascript_error_handler(log_entries.append)
    driver.script.remove_javascript_error_handler(id)
Show full example
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


@pytest.mark.driver_type("bidi")
def test_add_console_log_handler(driver):
    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)
    assert log_entries[0].text == "Hello, world!"


@pytest.mark.driver_type("bidi")
def test_remove_console_log_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_console_message_handler(log_entries.append)
    driver.script.remove_console_message_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0


@pytest.mark.driver_type("bidi")
def test_add_js_exception_handler(driver):
    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)
    assert log_entries[0].text == "Error: Not working"


@pytest.mark.driver_type("bidi")
def test_remove_js_exception_handler(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    log_entries = []

    id = driver.script.add_javascript_error_handler(log_entries.append)
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(By.ID, "consoleLog").click()
    assert len(log_entries) == 0
    log_entries = []
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_bidi_session }
  let(:wait) { Selenium::WebDriver::Wait.new(timeout: 2) }

  it 'adds console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_console_message_handler { |log| log_entries << log }

    driver.find_element(id: 'consoleLog').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Hello, world!'
  end

  it 'removes console message handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_console_message_handler { |log| log_entries << log }
    driver.script.remove_console_message_handler(id)

    driver.find_element(id: 'consoleLog').click
    expect(log_entries).to be_empty
  end

  it 'adds JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    driver.script.add_javascript_error_handler { |error| log_entries << error }

    driver.find_element(id: 'jsException').click
    wait.until { log_entries.any? }
    expect(log_entries.first&.text).to eq 'Error: Not working'
  end

  it 'removes JavaScript error handler' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'
    log_entries = []

    id = driver.script.add_javascript_error_handler { |error| log_entries << error }
    driver.script.remove_javascript_error_handler(id)

    driver.find_element(id: 'jsException').click
    expect(log_entries).to be_empty
  end
end

2 - WebDriver BiDi Network Features

These features are related to networking, and are made available via a “network” namespace.

The implementation of these features is being tracked here: #13993

Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi

Authentication Handlers

Request Handlers

Response Handlers

3 - WebDriver BiDi Script Features

These features are related to scripts, and are made available via a “script” namespace.

The implementation of these features is being tracked here: #13992

Remember that to use WebDriver BiDi, you must enable it in Options. For more details, see Enabling BiDi

Script Pinning

Execute Script

DOM Mutation Handlers

4 - Chrome DevTools Protocol

Examples of working with Chrome DevTools Protocol in Selenium. CDP support is temporary until WebDriver BiDi has been implemented.

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

Many browsers provide “DevTools” – a set of tools that are integrated with the browser that developers can use to debug web apps and explore the performance of their pages. Google Chrome’s DevTools make use of a protocol called the Chrome DevTools Protocol (or “CDP” for short). As the name suggests, this is not designed for testing, nor to have a stable API, so functionality is highly dependent on the version of the browser.

Selenium is working to implement a standards-based, cross-browser, stable alternative to CDP called [WebDriver BiDi]. Until the support for this new protocol has finished, Selenium plans to provide access to CDP features where applicable.

Using Chrome DevTools Protocol with Selenium

Chrome and Edge have a method to send basic CDP commands. This does not work for features that require bidirectional communication, and you need to know what domains to enable when and the exact names and types of domains/methods/parameters.

    Map<String, Object> cookie = new HashMap<>();
    cookie.put("name", "cheese");
    cookie.put("value", "gouda");
    cookie.put("domain", "www.selenium.dev");
    cookie.put("secure", true);
    ((HasCdp) driver).executeCdpCommand("Network.setCookie", cookie);
Show full example
package dev.selenium.bidi.cdp;

import dev.selenium.BaseTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chromium.HasCdp;

import java.util.HashMap;
import java.util.Map;

public class CdpTest extends BaseTest {
  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
  }

  @Test
  public void setCookie() {
    Map<String, Object> cookie = new HashMap<>();
    cookie.put("name", "cheese");
    cookie.put("value", "gouda");
    cookie.put("domain", "www.selenium.dev");
    cookie.put("secure", true);
    ((HasCdp) driver).executeCdpCommand("Network.setCookie", cookie);

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }
}
    cookie = {'name': 'cheese',
              'value': 'gouda',
              'domain': 'www.selenium.dev',
              'secure': True}

    driver.execute_cdp_cmd('Network.setCookie', cookie)
Show full example
def test_set_cookie(driver):
    cookie = {'name': 'cheese',
              'value': 'gouda',
              'domain': 'www.selenium.dev',
              'secure': True}

    driver.execute_cdp_cmd('Network.setCookie', cookie)

    driver.get('https://www.selenium.dev')
    cheese = driver.get_cookie(cookie['name'])

    assert cheese['value'] == 'gouda'
            var cookie = new Dictionary<string, object>
            {
                { "name", "cheese" },
                { "value", "gouda" },
                { "domain", "www.selenium.dev" },
                { "secure", true }
            };
            ((ChromeDriver)driver).ExecuteCdpCommand("Network.setCookie", cookie);
Show full example
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class CDPTest : BaseChromeTest
    {
        [TestMethod]
        public void SetCookie()
        {
            var cookie = new Dictionary<string, object>
            {
                { "name", "cheese" },
                { "value", "gouda" },
                { "domain", "www.selenium.dev" },
                { "secure", true }
            };
            ((ChromeDriver)driver).ExecuteCdpCommand("Network.setCookie", cookie);
            
            driver.Url = "https://www.selenium.dev";
            Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);

        }
    }
}
    driver.execute_cdp('Network.setCookie',
                       name: 'cheese',
                       value: 'gouda',
                       domain: 'www.selenium.dev',
                       secure: true)
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_session }

  it 'sets cookie' do
    driver.execute_cdp('Network.setCookie',
                       name: 'cheese',
                       value: 'gouda',
                       domain: 'www.selenium.dev',
                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end
end

To make working with CDP easier, and to provide access to the more advanced features, Selenium bindings automatically generate classes and methods for the most common domains. CDP methods and implementations can change from version to version, though, so you want to keep the version of Chrome and the version of DevTools matching. Selenium supports the 3 most recent versions of Chrome at any given time, and tries to time releases to ensure that access to the latest versions are available.

This limitation provides additional challenges for several bindings, where dynamically generated CDP support requires users to regularly update their code to reference the proper version of CDP. In some cases an idealized implementation has been created that should work for any version of CDP without the user needing to change their code, but that is not always available.

Examples of how to use CDP in your Selenium tests can be found on the following pages, but we want to call out a couple commonly cited examples that are of limited practical value.

  • Geo Location — almost all sites use the IP address to determine physical location, so setting an emulated geolocation rarely has the desired effect.
  • Overriding Device Metrics — Chrome provides a great API for setting Mobile Emulation in the Options classes, which is generally superior to attempting to do this with CDP.

4.1 - Chrome DevTools Logging Features

Logging features using CDP.

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

While Selenium 4 provides direct access to the Chrome DevTools Protocol, these methods will eventually be removed when WebDriver BiDi implemented.

Console Logs

    ((HasLogEvents) driver).onLogEvent(consoleEvent(e -> messages.add(e.getMessages().get(0))));
Show full example
package dev.selenium.bidi.cdp;

import static org.openqa.selenium.devtools.events.CdpEventTypes.consoleEvent;

import dev.selenium.BaseTest;

import java.time.Duration;
import java.util.concurrent.CopyOnWriteArrayList;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.HasLogEvents;
import org.openqa.selenium.support.ui.WebDriverWait;

public class LoggingTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void consoleLogs() {
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");
    CopyOnWriteArrayList<String> messages = new CopyOnWriteArrayList<>();

    ((HasLogEvents) driver).onLogEvent(consoleEvent(e -> messages.add(e.getMessages().get(0))));

    driver.findElement(By.id("consoleLog")).click();
    driver.findElement(By.id("consoleError")).click();

    wait.until(_d -> messages.size() > 1);
    Assertions.assertTrue(messages.contains("Hello, world!"));
    Assertions.assertTrue(messages.contains("I am console error"));
  }
}
    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
Show full example
import pytest
from selenium.webdriver.common.bidi.console import Console
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log


@pytest.mark.trio
async def test_console_log(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
            driver.find_element(by=By.ID, value='consoleLog').click()

        assert messages["message"] == "Hello, world!"


@pytest.mark.trio
async def test_js_error(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
            driver.find_element(by=By.ID, value='jsException').click()

        assert "Error: Not working" in messages.exception_details.exception.description
            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();
Show full example
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;

namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class LoggingTest : BaseChromeTest
    {
        [TestMethod]
        public async Task ConsoleLogs()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("consoleLog")).Click();
            driver.FindElement(By.Id("consoleError")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => messages.Count > 1);
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Hello, world!"));
            Assert.IsTrue(messages.Contains("I am console error"));
        }
        
        [TestMethod]
        public async Task JsErrors()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("jsException")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !messages.IsNullOrEmpty());
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Uncaught"));
        }
    }
}
    driver.on_log_event(:console) { |log| logs << log.args.first }
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_session }

  it 'listens for console logs' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    logs = []
    driver.on_log_event(:console) { |log| logs << log.args.first }

    driver.find_element(id: 'consoleLog').click
    driver.find_element(id: 'consoleError').click

    Selenium::WebDriver::Wait.new.until { logs.size > 1 }
    expect(logs).to include 'Hello, world!'
    expect(logs).to include 'I am console error'
  end

  it 'listens for js exception' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    exceptions = []
    driver.on_log_event(:exception) { |exception| exceptions << exception }

    driver.find_element(id: 'jsException').click

    Selenium::WebDriver::Wait.new.until { exceptions.any? }
    expect(exceptions.first&.description).to include 'Error: Not working'
  end
end

JavaScript Exceptions

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
Show full example
import pytest
from selenium.webdriver.common.bidi.console import Console
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log


@pytest.mark.trio
async def test_console_log(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_listener(Console.ALL) as messages:
            driver.find_element(by=By.ID, value='consoleLog').click()

        assert messages["message"] == "Hello, world!"


@pytest.mark.trio
async def test_js_error(driver):
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    async with driver.bidi_connection() as session:
        async with Log(driver, session).add_js_error_listener() as messages:
            driver.find_element(by=By.ID, value='jsException').click()

        assert "Error: Not working" in messages.exception_details.exception.description
            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();
Show full example
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;

namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class LoggingTest : BaseChromeTest
    {
        [TestMethod]
        public async Task ConsoleLogs()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptConsoleApiCalled += (_, e) =>
            {
                messages.Add(e.MessageContent);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("consoleLog")).Click();
            driver.FindElement(By.Id("consoleError")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => messages.Count > 1);
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Hello, world!"));
            Assert.IsTrue(messages.Contains("I am console error"));
        }
        
        [TestMethod]
        public async Task JsErrors()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html";

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            var messages = new List<string>();
            monitor.JavaScriptExceptionThrown += (_, e) =>
            {
                messages.Add(e.Message);
            };
            await monitor.StartEventMonitoring();

            driver.FindElement(By.Id("jsException")).Click();
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !messages.IsNullOrEmpty());
            monitor.StopEventMonitoring();

            Assert.IsTrue(messages.Contains("Uncaught"));
        }
    }
}
    driver.on_log_event(:exception) { |exception| exceptions << exception }
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Logging' do
  let(:driver) { start_session }

  it 'listens for console logs' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    logs = []
    driver.on_log_event(:console) { |log| logs << log.args.first }

    driver.find_element(id: 'consoleLog').click
    driver.find_element(id: 'consoleError').click

    Selenium::WebDriver::Wait.new.until { logs.size > 1 }
    expect(logs).to include 'Hello, world!'
    expect(logs).to include 'I am console error'
  end

  it 'listens for js exception' do
    driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    exceptions = []
    driver.on_log_event(:exception) { |exception| exceptions << exception }

    driver.find_element(id: 'jsException').click

    Selenium::WebDriver::Wait.new.until { exceptions.any? }
    expect(exceptions.first&.description).to include 'Error: Not working'
  end
end

4.2 - Chrome DevTools Network Features

Network features using CDP.

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

While Selenium 4 provides direct access to the Chrome DevTools Protocol, these methods will eventually be removed when WebDriver BiDi implemented.

Basic authentication

Some applications make use of browser authentication to secure pages. It used to be common to handle them in the URL, but browsers stopped supporting this. With this code you can insert the credentials into the header when necessary

    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
        credentials = base64.b64encode("admin:admin".encode()).decode()
        auth = {'authorization': 'Basic ' + credentials}
        await connection.session.execute(connection.devtools.network.set_extra_http_headers(Headers(auth)))
Show full example
import base64

import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.devtools.v134.network import Headers


@pytest.mark.trio
async def test_basic_auth(driver):
    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.network.enable())

        credentials = base64.b64encode("admin:admin".encode()).decode()
        auth = {'authorization': 'Basic ' + credentials}
        await connection.session.execute(connection.devtools.network.set_extra_http_headers(Headers(auth)))

        driver.get('https://the-internet.herokuapp.com/basic_auth')

    success = driver.find_element(by=By.TAG_NAME, value='p')
    assert success.text == 'Congratulations! You must have the proper credentials.'

@pytest.mark.trio
async def test_performance(driver):
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.performance.enable())
        metric_list = await connection.session.execute(connection.devtools.performance.get_metrics())

    metrics = {metric.name: metric.value for metric in metric_list}

    assert metrics["DevToolsCommandDuration"] > 0
    assert metrics["Frames"] == 12

@pytest.mark.trio
async def test_set_cookie(driver):
    async with driver.bidi_connection() as connection:
        execution = connection.devtools.network.set_cookie(
            name="cheese",
            value="gouda",
            domain="www.selenium.dev",
            secure=True
        )
        await connection.session.execute(execution)

    driver.get("https://www.selenium.dev")
    cheese = driver.get_cookie("cheese")

    assert cheese["value"] == "gouda"
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Network Interception

Both requests and responses can be recorded or transformed.

Response information

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Response transformation

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Request interception

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Performance Metrics

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.performance.enable())
        metric_list = await connection.session.execute(connection.devtools.performance.get_metrics())
Show full example
import base64

import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.devtools.v134.network import Headers


@pytest.mark.trio
async def test_basic_auth(driver):
    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.network.enable())

        credentials = base64.b64encode("admin:admin".encode()).decode()
        auth = {'authorization': 'Basic ' + credentials}
        await connection.session.execute(connection.devtools.network.set_extra_http_headers(Headers(auth)))

        driver.get('https://the-internet.herokuapp.com/basic_auth')

    success = driver.find_element(by=By.TAG_NAME, value='p')
    assert success.text == 'Congratulations! You must have the proper credentials.'

@pytest.mark.trio
async def test_performance(driver):
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.performance.enable())
        metric_list = await connection.session.execute(connection.devtools.performance.get_metrics())

    metrics = {metric.name: metric.value for metric in metric_list}

    assert metrics["DevToolsCommandDuration"] > 0
    assert metrics["Frames"] == 12

@pytest.mark.trio
async def test_set_cookie(driver):
    async with driver.bidi_connection() as connection:
        execution = connection.devtools.network.set_cookie(
            name="cheese",
            value="gouda",
            domain="www.selenium.dev",
            secure=True
        )
        await connection.session.execute(execution)

    driver.get("https://www.selenium.dev")
    cheese = driver.get_cookie("cheese")

    assert cheese["value"] == "gouda"
            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Setting Cookies

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
    async with driver.bidi_connection() as connection:
        execution = connection.devtools.network.set_cookie(
            name="cheese",
            value="gouda",
            domain="www.selenium.dev",
            secure=True
        )
        await connection.session.execute(execution)
Show full example
import base64

import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.devtools.v134.network import Headers


@pytest.mark.trio
async def test_basic_auth(driver):
    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.network.enable())

        credentials = base64.b64encode("admin:admin".encode()).decode()
        auth = {'authorization': 'Basic ' + credentials}
        await connection.session.execute(connection.devtools.network.set_extra_http_headers(Headers(auth)))

        driver.get('https://the-internet.herokuapp.com/basic_auth')

    success = driver.find_element(by=By.TAG_NAME, value='p')
    assert success.text == 'Congratulations! You must have the proper credentials.'

@pytest.mark.trio
async def test_performance(driver):
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    async with driver.bidi_connection() as connection:
        await connection.session.execute(connection.devtools.performance.enable())
        metric_list = await connection.session.execute(connection.devtools.performance.get_metrics())

    metrics = {metric.name: metric.value for metric in metric_list}

    assert metrics["DevToolsCommandDuration"] > 0
    assert metrics["Frames"] == 12

@pytest.mark.trio
async def test_set_cookie(driver):
    async with driver.bidi_connection() as connection:
        execution = connection.devtools.network.set_cookie(
            name="cheese",
            value="gouda",
            domain="www.selenium.dev",
            secure=True
        )
        await connection.session.execute(execution)

    driver.get("https://www.selenium.dev")
    cheese = driver.get_cookie("cheese")

    assert cheese["value"] == "gouda"
            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);
Show full example
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.DevTools;
using System.Linq;
using OpenQA.Selenium.DevTools.V132.Network;
using OpenQA.Selenium.DevTools.V132.Performance;


namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class NetworkTest : BaseTest
    {
        [TestInitialize]
        public void Startup()
        {
            StartDriver("132");
        }

        [TestMethod]
        public async Task BasicAuthentication()
        {
            var handler = new NetworkAuthenticationHandler()
            {
                UriMatcher = uri => uri.AbsoluteUri.Contains("herokuapp"),
                Credentials = new PasswordCredentials("admin", "admin")
            };
            var networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddAuthenticationHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://the-internet.herokuapp.com/basic_auth");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("Congratulations! You must have the proper credentials.",
                driver.FindElement(By.TagName("p")).Text);
        }

        [TestMethod]
        public async Task RecordNetworkResponse()
        {
            var contentType = new List<string>();

            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.NetworkResponseReceived += (_, e)  =>
            {
                contentType.Add(e.ResponseHeaders["content-type"]);
            };
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev/selenium/web/blank.html");
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("text/html; charset=utf-8", contentType[0]);
        }

        [TestMethod]
        public async Task TransformNetworkResponse()
        {
            var handler = new NetworkResponseHandler()
            {
                ResponseMatcher = _ => true,
                ResponseTransformer = _ => new HttpResponseData
                {
                    StatusCode = 200,
                    Body = "Creamy, delicious cheese!"
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddResponseHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Navigate().GoToUrl("https://www.selenium.dev");
            await networkInterceptor.StopMonitoring();

            var body = driver.FindElement(By.TagName("body"));
            Assert.AreEqual("Creamy, delicious cheese!", body.Text);
        }

        [TestMethod]
        public async Task TransformNetworkRequest()
        {
            var handler = new NetworkRequestHandler
            {
                RequestMatcher = request => request.Url.Contains("one.js"),
                RequestTransformer = request =>
                {
                    request.Url = request.Url.Replace("one", "two");

                    return request;
                }
            };
            INetwork networkInterceptor = driver.Manage().Network;
            networkInterceptor.AddRequestHandler(handler);
            await networkInterceptor.StartMonitoring();

            driver.Url = "https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html";
            driver.FindElement(By.TagName("button")).Click();
            await networkInterceptor.StopMonitoring();

            Assert.AreEqual("two", driver.FindElement(By.Id("result")).Text);
        }

        [TestMethod]
        public async Task PerformanceMetrics()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/frameset.html";

            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();

            await domains.Performance.Enable(new OpenQA.Selenium.DevTools.V132.Performance.EnableCommandSettings());
            var metricsResponse =
                await session.SendCommand<GetMetricsCommandSettings, GetMetricsCommandResponse>(
                    new GetMetricsCommandSettings()
                );

            var metrics = metricsResponse.Metrics.ToDictionary(
                dict => dict.Name,
                dict => dict.Value
            );

            Assert.IsTrue(metrics["DevToolsCommandDuration"] > 0);
            Assert.AreEqual(12, metrics["Frames"]);
        }

        [TestMethod]
        public async Task SetCookie()
        {
            var session = ((IDevTools)driver).GetDevToolsSession();
            var domains = session.GetVersionSpecificDomains<OpenQA.Selenium.DevTools.V132.DevToolsSessionDomains>();
            await domains.Network.Enable(new OpenQA.Selenium.DevTools.V132.Network.EnableCommandSettings());

            var cookieCommandSettings = new SetCookieCommandSettings
            {
                Name = "cheese",
                Value = "gouda",
                Domain = "www.selenium.dev",
                Secure = true
            };
            await domains.Network.SetCookie(cookieCommandSettings);

            driver.Url = "https://www.selenium.dev";
            OpenQA.Selenium.Cookie cheese = driver.Manage().Cookies.GetCookieNamed("cheese");
            Assert.AreEqual("gouda", cheese.Value);
        }

    }
}
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

Waiting for Downloads

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));
Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Network' do
  let(:driver) { start_session }

  it 'does basic authentication' do
    driver.register(username: 'admin',
                    password: 'admin',
                    uri: /herokuapp/)

    driver.get('https://the-internet.herokuapp.com/basic_auth')

    expect(driver.find_element(tag_name: 'p').text).to eq('Congratulations! You must have the proper credentials.')
  end

  it 'records network response' do
    content_type = []
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        content_type << response.headers['content-type']
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(content_type.first).to eq('text/html; charset=utf-8')
  end

  it 'transforms network response' do
    driver.intercept do |request, &continue|
      continue.call(request) do |response|
        response.body = 'Creamy, delicious cheese!' if request.url.include?('blank')
      end
    end

    driver.get('https://www.selenium.dev/selenium/web/blank.html')
    expect(driver.find_element(tag_name: 'body').text).to eq('Creamy, delicious cheese!')
  end

  it 'intercepts network request' do
    driver.intercept do |request, &continue|
      uri = URI(request.url)
      request.url = uri.to_s.gsub('one', 'two') if uri.path&.end_with?('one.js')
      continue.call(request)
    end

    driver.get('https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html')
    driver.find_element(tag_name: 'button').click
    expect(driver.find_element(id: 'result').text).to eq('two')
  end

  it 'gets performance metrics' do
    driver.get('https://www.selenium.dev/selenium/web/frameset.html')

    driver.devtools.performance.enable
    metric_list = driver.devtools.performance.get_metrics.dig('result', 'metrics')

    metrics = metric_list.each_with_object({}) do |metric, hash|
      hash[metric['name']] = metric['value']
    end

    expect(metrics['DevToolsCommandDuration']).to be > 0
    expect(metrics['Frames']).to eq 12
  end

  it 'sets cookie' do
    driver.devtools.network.set_cookie(name: 'cheese',
                                       value: 'gouda',
                                       domain: 'www.selenium.dev',
                                       secure: true)

    driver.get('https://www.selenium.dev')
    cheese = driver.manage.cookie_named('cheese')

    expect(cheese[:value]).to eq 'gouda'
  end

  it 'waits for downloads', except: {platform: :windows} do
    driver.get('https://www.selenium.dev/selenium/web/downloads/download.html')

    driver.devtools.browser.set_download_behavior(behavior: 'allow',
                                                  download_path: '',
                                                  events_enabled: true)

    driver.devtools.browser.on(:download_progress) do |progress|
      @completed = progress['state'] == 'completed'
    end

    driver.find_element(id: 'file-2').click

    expect { Selenium::WebDriver::Wait.new.until { @completed } }.not_to raise_exception
  end
end

4.3 - Chrome DevTools Script Features

Script features using CDP.

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

While Selenium 4 provides direct access to the Chrome DevTools Protocol, these methods will eventually be removed when WebDriver BiDi implemented.

Script Pinning

    ScriptKey key = ((JavascriptExecutor) driver).pin("return arguments;");
    List<Object> arguments =
        (List<Object>) ((JavascriptExecutor) driver).executeScript(key, 1, true, element);
Show full example
package dev.selenium.bidi.cdp;

import static org.openqa.selenium.devtools.events.CdpEventTypes.domMutation;

import dev.selenium.BaseTest;

import java.time.Duration;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.logging.HasLogEvents;
import org.openqa.selenium.support.ui.WebDriverWait;

public class ScriptTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void pinScript() {
    driver.get("https://www.selenium.dev/selenium/web/xhtmlTest.html");
    WebElement element = driver.findElement(By.id("id1"));

    ScriptKey key = ((JavascriptExecutor) driver).pin("return arguments;");
    List<Object> arguments =
        (List<Object>) ((JavascriptExecutor) driver).executeScript(key, 1, true, element);

    Assertions.assertEquals(List.of(1L, true, element), arguments);
  }

  @Test
  public void mutatedElements() {
    driver.get("https://www.selenium.dev/selenium/web/dynamic.html");
    CopyOnWriteArrayList<WebElement> mutations = new CopyOnWriteArrayList<>();

    ((HasLogEvents) driver).onLogEvent(domMutation(e -> mutations.add(e.getElement())));

    driver.findElement(By.id("reveal")).click();

    wait.until(_d -> !mutations.isEmpty());
    Assertions.assertEquals(mutations.get(0), driver.findElement(By.id("revealed")));
  }
}
            var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
            var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);
Show full example
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;

namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class ScriptTest : BaseChromeTest
    {
        [TestMethod]
        public async Task PinScript()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/xhtmlTest.html";
            var element = driver.FindElement(By.Id("id1"));

            var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
            var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);

            var expected = new List<object>
            {
                1L,
                true,
                element
            };
            CollectionAssert.AreEqual(expected, (ICollection)arguments);
        }

        [TestMethod]
        public async Task MutatedElements()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/dynamic.html";
            var mutations = new List<IWebElement>();

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            monitor.DomMutated += (_, e) =>
            {
                var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
                mutations.Add(driver.FindElement(locator));
            };
            await monitor.StartEventMonitoring();
            await monitor.EnableDomMutationMonitoring();

            driver.FindElement(By.Id("reveal")).Click();
            
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !mutations.IsNullOrEmpty());
            await monitor.DisableDomMutationMonitoring();
            monitor.StopEventMonitoring();

            var revealed = driver.FindElement(By.Id("revealed")); 
            Assert.AreEqual(revealed, mutations[0]);
        }
    }
}
    key = driver.pin_script('return arguments;')
    arguments = driver.execute_script(key, 1, true, element)
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Script' do
  let(:driver) { start_session }

  it 'pins script' do
    driver.get('https://www.selenium.dev/selenium/web/xhtmlTest.html')
    element = driver.find_element(id: 'id1')

    key = driver.pin_script('return arguments;')
    arguments = driver.execute_script(key, 1, true, element)

    expect(arguments).to eq([1, true, element])
  end

  it 'gets mutated elements' do
    driver.get 'https://www.selenium.dev/selenium/web/dynamic.html'

    mutations = []
    driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }

    driver.find_element(id: 'reveal').click
    Selenium::WebDriver::Wait.new(timeout: 30).until { mutations.any? }

    expect(mutations).to include(driver.find_element(id: 'revealed'))
  end
end

DOM Mutation Handlers

Show full example
package dev.selenium.bidi.cdp;

import com.google.common.net.MediaType;
import dev.selenium.BaseTest;
import java.net.*;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.NetworkInterceptor;
import org.openqa.selenium.devtools.v134.browser.Browser;
import org.openqa.selenium.devtools.v134.network.Network;
import org.openqa.selenium.devtools.v134.performance.Performance;
import org.openqa.selenium.devtools.v134.performance.model.Metric;
import org.openqa.selenium.remote.http.*;
import org.openqa.selenium.support.ui.WebDriverWait;

public class NetworkTest extends BaseTest {

  @BeforeEach
  public void createSession() {
    driver = new ChromeDriver();
    wait = new WebDriverWait(driver, Duration.ofSeconds(10));
  }

  @Test
  public void basicAuthentication() {
    Predicate<URI> uriPredicate = uri -> uri.toString().contains("herokuapp.com");
    Supplier<Credentials> authentication = UsernameAndPassword.of("admin", "admin");
    ((HasAuthentication) driver).register(uriPredicate, authentication);

    driver.get("https://the-internet.herokuapp.com/basic_auth");

    String successMessage = "Congratulations! You must have the proper credentials.";
    WebElement elementMessage = driver.findElement(By.tagName("p"));
    Assertions.assertEquals(successMessage, elementMessage.getText());
  }

  @Test
  public void recordResponse() {
    CopyOnWriteArrayList<String> contentType = new CopyOnWriteArrayList<>();

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      HttpResponse res = next.execute(req);
                      contentType.add(res.getHeader("Content-Type"));
                      return res;
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
      wait.until(_d -> contentType.size() > 1);
    }

    Assertions.assertEquals("text/html; charset=utf-8", contentType.get(0));
  }

  @Test
  public void transformResponses() {
    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            Route.matching(req -> true)
                .to(
                    () ->
                        req ->
                            new HttpResponse()
                                .setStatus(200)
                                .addHeader("Content-Type", MediaType.HTML_UTF_8.toString())
                                .setContent(Contents.utf8String("Creamy, delicious cheese!"))))) {
      driver.get("https://www.selenium.dev/selenium/web/blank.html");
    }

    WebElement body = driver.findElement(By.tagName("body"));
    Assertions.assertEquals("Creamy, delicious cheese!", body.getText());
  }

  @Test
  public void interceptRequests() {
    AtomicBoolean completed = new AtomicBoolean(false);

    try (NetworkInterceptor ignored =
        new NetworkInterceptor(
            driver,
            (Filter)
                next ->
                    req -> {
                      if (req.getUri().contains("one.js")) {
                        req =
                            new HttpRequest(
                                HttpMethod.GET, req.getUri().replace("one.js", "two.js"));
                      }
                      completed.set(true);
                      return next.execute(req);
                    })) {
      driver.get("https://www.selenium.dev/selenium/web/devToolsRequestInterceptionTest.html");
      driver.findElement(By.tagName("button")).click();
    }

    Assertions.assertEquals("two", driver.findElement(By.id("result")).getText());
  }

  @Test
  public void performanceMetrics() {
    driver.get("https://www.selenium.dev/selenium/web/frameset.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(Performance.enable(Optional.empty()));
    List<Metric> metricList = devTools.send(Performance.getMetrics());

    Map<String, Number> metrics = new HashMap<>();
    for (Metric metric : metricList) {
      metrics.put(metric.getName(), metric.getValue());
    }

    Assertions.assertTrue(metrics.get("DevToolsCommandDuration").doubleValue() > 0);
    Assertions.assertEquals(12, metrics.get("Frames").intValue());
  }

  @Test
  public void setCookie() {
    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Network.setCookie(
                    "cheese",
                    "gouda",
                    Optional.empty(),
                    Optional.of("www.selenium.dev"),
                    Optional.empty(),
                    Optional.of(true),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty()));

    driver.get("https://www.selenium.dev");
    Cookie cheese = driver.manage().getCookieNamed("cheese");
    Assertions.assertEquals("gouda", cheese.getValue());
  }

  @Test
  public void waitForDownload() {
    driver.get("https://www.selenium.dev/selenium/web/downloads/download.html");

    DevTools devTools = ((HasDevTools) driver).getDevTools();
    devTools.createSession();

    devTools.send(
            Browser.setDownloadBehavior(
                    Browser.SetDownloadBehaviorBehavior.ALLOWANDNAME,
                    Optional.empty(),
                    Optional.of(""),
                    Optional.of(true)));

    AtomicBoolean completed = new AtomicBoolean(false);
    devTools.addListener(
            Browser.downloadProgress(),
            e -> completed.set(Objects.equals(e.getState().toString(), "completed")));

    driver.findElement(By.id("file-2")).click();

    Assertions.assertDoesNotThrow(() -> wait.until(_d -> completed));
  }
}
    async with driver.bidi_connection() as session:
        async with Log(driver, session).mutation_events() as event:
Show full example
import pytest
import trio
from selenium.webdriver.common.by import By
from selenium.webdriver.common.log import Log
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

@pytest.mark.trio
async def test_mutation(driver):
    async with driver.bidi_connection() as session:
        async with Log(driver, session).mutation_events() as event:
            await trio.to_thread.run_sync(lambda: driver.get('https://www.selenium.dev/selenium/web/dynamic.html'))
            await trio.to_thread.run_sync(lambda: WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.ID, "reveal"))))
            await trio.to_thread.run_sync(lambda: driver.find_element(By.ID, "reveal").click())

    assert event["element"] == driver.find_element(By.ID, "revealed")
            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            monitor.DomMutated += (_, e) =>
            {
                var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
                mutations.Add(driver.FindElement(locator));
            };
            await monitor.StartEventMonitoring();
            await monitor.EnableDomMutationMonitoring();
Show full example
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;

namespace SeleniumDocs.BiDi.CDP
{
    [TestClass]
    public class ScriptTest : BaseChromeTest
    {
        [TestMethod]
        public async Task PinScript()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/xhtmlTest.html";
            var element = driver.FindElement(By.Id("id1"));

            var key = await new JavaScriptEngine(driver).PinScript("return arguments;");
            var arguments = ((WebDriver)driver).ExecuteScript(key, 1, true, element);

            var expected = new List<object>
            {
                1L,
                true,
                element
            };
            CollectionAssert.AreEqual(expected, (ICollection)arguments);
        }

        [TestMethod]
        public async Task MutatedElements()
        {
            driver.Url = "https://www.selenium.dev/selenium/web/dynamic.html";
            var mutations = new List<IWebElement>();

            using IJavaScriptEngine monitor = new JavaScriptEngine(driver);
            monitor.DomMutated += (_, e) =>
            {
                var locator = By.CssSelector($"*[data-__webdriver_id='{e.AttributeData.TargetId}']");
                mutations.Add(driver.FindElement(locator));
            };
            await monitor.StartEventMonitoring();
            await monitor.EnableDomMutationMonitoring();

            driver.FindElement(By.Id("reveal")).Click();
            
            new WebDriverWait(driver, TimeSpan.FromSeconds(5)).Until(_ => !mutations.IsNullOrEmpty());
            await monitor.DisableDomMutationMonitoring();
            monitor.StopEventMonitoring();

            var revealed = driver.FindElement(By.Id("revealed")); 
            Assert.AreEqual(revealed, mutations[0]);
        }
    }
}
    driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }
Show full example
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'Script' do
  let(:driver) { start_session }

  it 'pins script' do
    driver.get('https://www.selenium.dev/selenium/web/xhtmlTest.html')
    element = driver.find_element(id: 'id1')

    key = driver.pin_script('return arguments;')
    arguments = driver.execute_script(key, 1, true, element)

    expect(arguments).to eq([1, true, element])
  end

  it 'gets mutated elements' do
    driver.get 'https://www.selenium.dev/selenium/web/dynamic.html'

    mutations = []
    driver.on_log_event(:mutation) { |mutation| mutations << mutation.element }

    driver.find_element(id: 'reveal').click
    Selenium::WebDriver::Wait.new(timeout: 30).until { mutations.any? }

    expect(mutations).to include(driver.find_element(id: 'revealed'))
  end
end

5 - BiDirectional API (W3C compliant)

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

The following list of APIs will be growing as the WebDriver BiDirectional Protocol grows and browser vendors implement the same. Additionally, Selenium will try to support real-world use cases that internally use a combination of W3C BiDi protocol APIs.

If there is additional functionality you’d like to see, please raise a feature request.

5.1 - Browsing Context

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

Commands

This section contains the APIs related to browsing context commands.

Open a new window

Creates a new browsing context in a new window.

Selenium v4.8

    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Open a new tab

Creates a new browsing context in a new tab.

Selenium v4.8

    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Use existing window handle

Creates a browsing context for the existing tab/window to run commands.

Selenium v4.8

    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Open a window with a reference browsing context

A reference browsing context is a top-level browsing context. The API allows to pass the reference browsing context, which is used to create a new window. The implementation is operating system specific.

Selenium v4.8

    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Open a tab with a reference browsing context

A reference browsing context is a top-level browsing context. The API allows to pass the reference browsing context, which is used to create a new tab. The implementation is operating system specific.

Selenium v4.8

    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Selenium v4.8

    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Selenium v4.8

    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Get browsing context tree

Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context.

Selenium v4.8

    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Get browsing context tree with depth

Provides a tree of all browsing contexts descending from the parent browsing context, including the parent browsing context upto the depth value passed.

Selenium v4.8

    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Get All Top level browsing contexts

Selenium v4.8

    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.20.0

    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Close a tab/window

Selenium v4.8

    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.8

    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Activate a browsing context

Selenium v4.14.1

        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})
    await window1.activate()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Reload a browsing context

Selenium v4.13.0

        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    await browsingContext.reload(undefined, 'complete')
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Handle user prompt

Selenium v4.13.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    await browsingContext.handleUserPrompt(true, userText)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Capture Screenshot

Selenium v4.13.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    const response = await browsingContext.captureScreenshot()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Capture Viewport Screenshot

Selenium v4.14.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Capture Element Screenshot

Selenium v4.14.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    const response = await browsingContext.captureElementScreenshot(elementId)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Set Viewport

Selenium v4.14.1

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.15

    await browsingContext.setViewport(250, 300)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Selenium v4.14.1

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.10

    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Selenium v4.16.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.17

    await browsingContext.back()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Selenium v4.16.0

    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.17

    await browsingContext.forward()
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Traverse history

Selenium v4.16.0

        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Rectangle;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.BiDiException;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationResult;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.print.PrintOptions;
import org.openqa.selenium.remote.RemoteWebElement;

import static org.openqa.selenium.support.ui.ExpectedConditions.titleIs;
import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;

class BrowsingContextTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testCreateABrowsingContextForGivenId() {
        String id = driver.getWindowHandle();
        BrowsingContext browsingContext = new BrowsingContext(driver, id);
        Assertions.assertEquals(id, browsingContext.getId());
    }

    @Test
    void testCreateAWindow() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.WINDOW);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateAWindowWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATab() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testCreateATabWithAReferenceContext() {
        BrowsingContext
                browsingContext =
                new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle());
        Assertions.assertNotNull(browsingContext.getId());
    }

    @Test
    void testNavigateToAUrl() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testNavigateToAUrlWithReadinessState() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        NavigationResult info = browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html",
                ReadinessState.COMPLETE);

        Assertions.assertNotNull(browsingContext.getId());
        Assertions.assertNotNull(info.getNavigationId());
        Assertions.assertTrue(info.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testGetTreeWithAChild() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree();

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertEquals(1, info.getChildren().size());
        Assertions.assertEquals(referenceContextId, info.getId());
        Assertions.assertTrue(info.getChildren().get(0).getUrl().contains("formPage.html"));
    }

    @Test
    void testGetTreeWithDepth() {
        String referenceContextId = driver.getWindowHandle();
        BrowsingContext parentWindow = new BrowsingContext(driver, referenceContextId);

        parentWindow.navigate("https://www.selenium.dev/selenium/web/iframes.html", ReadinessState.COMPLETE);

        List<BrowsingContextInfo> contextInfoList = parentWindow.getTree(0);

        Assertions.assertEquals(1, contextInfoList.size());
        BrowsingContextInfo info = contextInfoList.get(0);
        Assertions.assertNull(info.getChildren()); // since depth is 0
        Assertions.assertEquals(referenceContextId, info.getId());
    }

    @Test
    void testGetAllTopLevelContexts() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        List<BrowsingContextInfo> contextInfoList = window1.getTopLevelContexts();

        Assertions.assertEquals(2, contextInfoList.size());
    }

    @Test
    void testCloseAWindow() {
        BrowsingContext window1 = new BrowsingContext(driver, WindowType.WINDOW);
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window2.close();

        Assertions.assertThrows(BiDiException.class, window2::getTree);
    }

    @Test
    void testCloseATab() {
        BrowsingContext tab1 = new BrowsingContext(driver, WindowType.TAB);
        BrowsingContext tab2 = new BrowsingContext(driver, WindowType.TAB);

        tab2.close();

        Assertions.assertThrows(BiDiException.class, tab2::getTree);
    }

    @Test
    void testActivateABrowsingContext() {
        BrowsingContext window1 = new BrowsingContext(driver, driver.getWindowHandle());
        BrowsingContext window2 = new BrowsingContext(driver, WindowType.WINDOW);

        window1.activate();

        boolean isFocused = (boolean) ((JavascriptExecutor) driver).executeScript("return document.hasFocus();");

        Assertions.assertTrue(isFocused);
    }

    @Test
    void testReloadABrowsingContext() {
        BrowsingContext browsingContext = new BrowsingContext(driver, WindowType.TAB);

        browsingContext.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

        NavigationResult reloadInfo = browsingContext.reload(ReadinessState.INTERACTIVE);

        Assertions.assertNotNull(reloadInfo.getNavigationId());
        Assertions.assertTrue(reloadInfo.getUrl().contains("/bidi/logEntryAdded.html"));
    }

    @Test
    void testHandleUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt();

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testAcceptUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testDismissUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("alert")).click();

        browsingContext.handleUserPrompt("true");

        Assertions.assertTrue(driver.getPageSource().contains("Testing Alerts and Stuff"));
    }

    @Test
    void testPassUserTextToUserPrompt() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(true, userText);

        Assertions.assertTrue(driver.getPageSource().contains(userText));
    }

    @Test
    void testDismissUserPromptWithText() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        driver.findElement(By.id("prompt-with-default")).click();

        String userText = "Selenium automates browsers";
        browsingContext.handleUserPrompt(false, userText);

        Assertions.assertFalse(driver.getPageSource().contains(userText));
    }

    @Test
    void textCaptureScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/alerts.html");

        String screenshot = browsingContext.captureScreenshot();

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureViewportScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/coordinates_tests/simple_page.html");

        WebElement element = driver.findElement(By.id("box"));
        Rectangle elementRectangle = element.getRect();

        String screenshot =
                browsingContext.captureBoxScreenshot(
                        elementRectangle.getX(), elementRectangle.getY(), 5, 5);

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textCaptureElementScreenshot() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        WebElement element = driver.findElement(By.id("checky"));

        String screenshot = browsingContext.captureElementScreenshot(((RemoteWebElement) element).getId());

        Assertions.assertTrue(screenshot.length() > 0);
    }

    @Test
    void textSetViewport() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300);

        List<Long> newViewportSize =
                (List<Long>)
                        ((JavascriptExecutor) driver)
                                .executeScript("return [window.innerWidth, window.innerHeight];");

        Assertions.assertEquals(250, newViewportSize.get(0));
        Assertions.assertEquals(300, newViewportSize.get(1));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void textSetViewportWithDevicePixelRatio() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        driver.get("https://www.selenium.dev/selenium/web/formPage.html");

        browsingContext.setViewport(250, 300, 5);

        Long newDevicePixelRatio =
                (Long) ((JavascriptExecutor) driver).executeScript("return window.devicePixelRatio");

        Assertions.assertEquals(5, newDevicePixelRatio);
    }

    @Test
    void testPrintPage() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());

        driver.get("https://www.selenium.dev/selenium/web/formPage.html");
        PrintOptions printOptions = new PrintOptions();

        String printPage = browsingContext.print(printOptions);

        Assertions.assertTrue(printPage.length() > 0);
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void testNavigateBackInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canNavigateForwardInTheBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.back();
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));

        browsingContext.forward();
        wait.until(titleIs("We Arrive Here"));
    }

    @Test
    @Disabled("Supported by Firefox Nightly 124")
    void canTraverseBrowserHistory() {
        BrowsingContext browsingContext = new BrowsingContext(driver, driver.getWindowHandle());
        browsingContext.navigate("https://www.selenium.dev/selenium/web/formPage.html", ReadinessState.COMPLETE);

        wait.until(visibilityOfElementLocated(By.id("imageButton"))).submit();
        wait.until(titleIs("We Arrive Here"));

        browsingContext.traverseHistory(-1);
        Assertions.assertTrue(driver.getPageSource().contains("We Leave From Here"));
    }
}

Selenium v4.17

    await browsingContext.traverseHistory(-1)
Show full example
const {By, until, Builder} = require("selenium-webdriver");
const firefox = require('selenium-webdriver/firefox');
const BrowsingContext = require('selenium-webdriver/bidi/browsingContext');
const assert = require("assert");

describe('Browsing Context', function () {
  let driver
  let startIndex = 0
  let endIndex = 5
  let pdfMagicNumber = 'JVBER'
  let pngMagicNumber = 'iVBOR'

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test create a browsing context for given id', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    assert.equal(browsingContext.id, id)
  })

  it('test create a window', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a window with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'window',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test create a tab with a reference context', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
      referenceContext: await driver.getWindowHandle(),
    })
    assert.notEqual(browsingContext.id, null)
  })

  it('test navigate to a url', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    let info = await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test navigate to a url with readiness state', async function () {
    const browsingContext = await BrowsingContext(driver, {
      type: 'tab',
    })

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html',
      'complete'
    )

    assert.notEqual(browsingContext.id, null)
    assert.notEqual(info.navigationId, null)
    assert(info.url.includes('/bidi/logEntryAdded.html'))
  })

  it('test get tree with a child', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree()
    assert.equal(contextInfo.children.length, 1)
    assert.equal(contextInfo.id, browsingContextId)
    assert(contextInfo.children[0]['url'].includes('formPage.html'))
  })

  it('test get tree with depth', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const parentWindow = await BrowsingContext(driver, {
      browsingContextId: browsingContextId,
    })
    await parentWindow.navigate('https://www.selenium.dev/selenium/web/iframes.html', 'complete')

    const contextInfo = await parentWindow.getTree(0)
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.id, browsingContextId)
  })

  it('test close a window', async function () {
    const window1 = await BrowsingContext(driver, {type: 'window'})
    const window2 = await BrowsingContext(driver, {type: 'window'})

    await window2.close()

    assert.doesNotThrow(async function () {
      await window1.getTree()
    })
    await assert.rejects(window2.getTree(), {message: 'no such frame'})
  })

  it('test close a tab', async function () {
    const tab1 = await BrowsingContext(driver, {type: 'tab'})
    const tab2 = await BrowsingContext(driver, {type: 'tab'})

    await tab2.close()

    assert.doesNotThrow(async function () {
      await tab1.getTree()
    })
    await assert.rejects(tab2.getTree(), {message: 'no such frame'})
  })

  it('can print PDF with all valid parameters', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/printPage.html")
    const result = await browsingContext.printPage({
      orientation: 'landscape',
      scale: 1,
      background: true,
      width: 30,
      height: 30,
      top: 1,
      bottom: 1,
      left: 1,
      right: 1,
      shrinkToFit: true,
      pageRanges: ['1-2'],
    })

    let base64Code = result.data.slice(0, 5)
    assert.strictEqual(base64Code, 'JVBER')
  })

  it('can take box screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureBoxScreenshot(5, 5, 10, 10)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can take element screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/formPage.html")
    const element = await driver.findElement(By.id('checky'))
    const elementId = await element.getId()
    const response = await browsingContext.captureElementScreenshot(elementId)

    const base64code = response.slice(0, 5)
    assert.equal(base64code, 'iVBOR')
  })

  it('can activate a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await BrowsingContext(driver, {
      type: 'window',
    })

    const result = await driver.executeScript('return document.hasFocus();')

    assert.equal(result, false)

    await window1.activate()
    const result2 = await driver.executeScript('return document.hasFocus();')

    assert.equal(result2, true)
  })

  it('can handle user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt()

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can accept user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(true)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can dismiss user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    await browsingContext.handleUserPrompt(false)

    const result = await driver.getTitle()

    assert.equal(result, 'Testing Alerts')
  })

  it('can pass user text to user prompt', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(undefined, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can accept user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('prompt')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(true, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), true)
  })

  it('can dismiss user prompt with user text', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/alerts.html")

    await driver.findElement(By.id('alert')).click()

    await driver.wait(until.alertIsPresent())

    const userText = 'Selenium automates browsers'

    await browsingContext.handleUserPrompt(false, userText)

    const result = await driver.getPageSource()
    assert.equal(result.includes(userText), false)
  })

  it('can set viewport', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await driver.get("https://www.selenium.dev/selenium/web/blank.html")

    await browsingContext.setViewport(250, 300)

    const result = await driver.executeScript('return [window.innerWidth, window.innerHeight];')
    assert.equal(result[0], 250)
    assert.equal(result[1], 300)
  })

  it('can reload a browsing context', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const result = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    await browsingContext.reload(undefined, 'complete')
    assert.notEqual(result.navigationId, null)
    assert(result.url.includes('/bidi/logEntryAdded.html'))
  })

  it('can take screenshot', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    const response = await browsingContext.captureScreenshot()
    const base64code = response.slice(startIndex, endIndex)
    assert.equal(base64code, pngMagicNumber)
  })

  it('can traverse browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.traverseHistory(-1)

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate back in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)
  })

  it('can navigate forward in browser history', async function () {
    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/formPage.html', 'complete')

    await driver.wait(until.elementLocated(By.id('imageButton'))).submit()
    await driver.wait(until.titleIs('We Arrive Here'), 2500)

    await browsingContext.back()

    const source = await driver.getPageSource()

    assert.equal(source.includes('We Leave From Here'), true)

    await browsingContext.forward()

    await driver.wait(until.titleIs('We Arrive Here'), 2500)
  });

  it.skip('Get All Top level browsing contexts', async () => {
    const id = await driver.getWindowHandle()
    const window1 = await BrowsingContext(driver, {
      browsingContextId: id,
    })
    await BrowsingContext(driver, { type: 'window' })
    const res = await window1.getTopLevelContexts()
    assert.equal(res.length, 2)
  })
})

Events

This section contains the APIs related to browsing context events.

Browsing Context Created Event

Selenium v4.10

    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Selenium v4.9.2

    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
Show full example
const BrowsingContextInspector = require("selenium-webdriver/bidi/browsingContextInspector");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const {Builder} = require("selenium-webdriver");

describe('Browsing Context Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to window browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
    const windowHandle = await driver.getWindowHandle()
    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to tab browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('tab')
    const tabHandle = await driver.getWindowHandle()

    assert.equal(contextInfo.id, tabHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to dom content loaded event', async function () {
    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to browsing context loaded event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to fragment navigated event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('linkToAnchorOnThisPage'), true)
  })

  it('can listen to browsing context destroyed event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()

    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })
})

Dom Content loaded Event

Selenium v4.10

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Selenium v4.9.2

    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')
Show full example
const BrowsingContextInspector = require("selenium-webdriver/bidi/browsingContextInspector");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const {Builder} = require("selenium-webdriver");

describe('Browsing Context Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to window browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
    const windowHandle = await driver.getWindowHandle()
    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to tab browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('tab')
    const tabHandle = await driver.getWindowHandle()

    assert.equal(contextInfo.id, tabHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to dom content loaded event', async function () {
    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to browsing context loaded event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to fragment navigated event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('linkToAnchorOnThisPage'), true)
  })

  it('can listen to browsing context destroyed event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()

    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })
})

Browsing Context Loaded Event

Selenium v4.10

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Selenium v4.9.2

    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')
Show full example
const BrowsingContextInspector = require("selenium-webdriver/bidi/browsingContextInspector");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const {Builder} = require("selenium-webdriver");

describe('Browsing Context Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to window browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
    const windowHandle = await driver.getWindowHandle()
    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to tab browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('tab')
    const tabHandle = await driver.getWindowHandle()

    assert.equal(contextInfo.id, tabHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to dom content loaded event', async function () {
    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to browsing context loaded event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to fragment navigated event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('linkToAnchorOnThisPage'), true)
  })

  it('can listen to browsing context destroyed event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()

    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })
})

Selenium v4.15

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Fragment Navigated Event

Selenium v4.15

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Selenium v4.15.0

    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')
Show full example
const BrowsingContextInspector = require("selenium-webdriver/bidi/browsingContextInspector");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const {Builder} = require("selenium-webdriver");

describe('Browsing Context Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to window browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
    const windowHandle = await driver.getWindowHandle()
    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to tab browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('tab')
    const tabHandle = await driver.getWindowHandle()

    assert.equal(contextInfo.id, tabHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to dom content loaded event', async function () {
    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to browsing context loaded event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to fragment navigated event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('linkToAnchorOnThisPage'), true)
  })

  it('can listen to browsing context destroyed event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()

    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })
})

User Prompt Opened Event

Selenium v4.15

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

User Prompt Closed Event

Selenium v4.15

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Browsing Context Destroyed Event

Selenium v4.18

        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.BrowsingContextInspector;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContextInfo;
import org.openqa.selenium.bidi.browsingcontext.NavigationInfo;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.browsingcontext.UserPromptClosed;
import org.openqa.selenium.bidi.browsingcontext.UserPromptOpened;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class BrowsingContextInspectorTest extends BaseTest {
    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToWindowBrowsingContextCreatedEvent()
        throws ExecutionException, InterruptedException, TimeoutException {
    try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
        CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

        inspector.onBrowsingContextCreated(future::complete);

        String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

        BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

        Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToTabBrowsingContextCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextCreated(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
        }
    }

    @Test
    void canListenToDomContentLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onDomContentLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToBrowsingContextLoadedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onBrowsingContextLoaded(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToNavigationStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();
            inspector.onNavigationStarted(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("bidi/logEntryAdded"));
        }
    }

    @Test
    void canListenToFragmentNavigatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<NavigationInfo> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html", ReadinessState.COMPLETE);

            inspector.onFragmentNavigated(future::complete);

            context.navigate("https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage", ReadinessState.COMPLETE);

            NavigationInfo navigationInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertTrue(navigationInfo.getUrl().contains("linkToAnchorOnThisPage"));
        }
    }

    @Test
    void canListenToUserPromptOpenedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptOpened> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptOpened(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("alert")).click();

            UserPromptOpened userPromptOpened = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptOpened.getBrowsingContextId());
        }
    }

    @Test
    void canListenToUserPromptClosedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<UserPromptClosed> future = new CompletableFuture<>();

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());
            inspector.onUserPromptClosed(future::complete);

            driver.get("https://www.selenium.dev/selenium/web/alerts.html");

            driver.findElement(By.id("prompt")).click();

            context.handleUserPrompt(true, "selenium");

            UserPromptClosed userPromptClosed = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals(context.getId(), userPromptClosed.getBrowsingContextId());
        }
    }

    @Test
    void canListenToBrowsingContextDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (BrowsingContextInspector inspector = new BrowsingContextInspector(driver)) {
            CompletableFuture<BrowsingContextInfo> future = new CompletableFuture<>();

            inspector.onBrowsingContextDestroyed(future::complete);

            String windowHandle = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();

            driver.close();

            BrowsingContextInfo browsingContextInfo = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals(windowHandle, browsingContextInfo.getId());
            Assertions.assertTrue(browsingContextInfo.getUrl().contains("about:blank"));
        }
    }
}

Selenium v4.18.0

    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()
Show full example
const BrowsingContextInspector = require("selenium-webdriver/bidi/browsingContextInspector");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const {Builder} = require("selenium-webdriver");

describe('Browsing Context Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to window browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')
    const windowHandle = await driver.getWindowHandle()
    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to tab browsing context created event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextCreated((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('tab')
    const tabHandle = await driver.getWindowHandle()

    assert.equal(contextInfo.id, tabHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })

  it('can listen to dom content loaded event', async function () {
    const browsingContextInspector = await BrowsingContextInspector(driver)
    let navigationInfo = null
    await browsingContextInspector.onDomContentLoaded((entry) => {
      navigationInfo = entry
    })

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to browsing context loaded event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    await browsingContextInspector.onBrowsingContextLoaded((entry) => {
      navigationInfo = entry
    })
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('/bidi/logEntryAdded.html'), true)
  })

  it('can listen to fragment navigated event', async function () {
    let navigationInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)

    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: await driver.getWindowHandle(),
    })
    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html', 'complete')

    await browsingContextInspector.onFragmentNavigated((entry) => {
      navigationInfo = entry
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/linked_image.html#linkToAnchorOnThisPage', 'complete')

    assert.equal(navigationInfo.browsingContextId, browsingContext.id)
    assert.strictEqual(navigationInfo.url.includes('linkToAnchorOnThisPage'), true)
  })

  it('can listen to browsing context destroyed event', async function () {
    let contextInfo = null
    const browsingContextInspector = await BrowsingContextInspector(driver)
    await browsingContextInspector.onBrowsingContextDestroyed((entry) => {
      contextInfo = entry
    })

    await driver.switchTo().newWindow('window')

    const windowHandle = await driver.getWindowHandle()
    await driver.close()

    assert.equal(contextInfo.id, windowHandle)
    assert.equal(contextInfo.url, 'about:blank')
    assert.equal(contextInfo.children, null)
    assert.equal(contextInfo.parentBrowsingContext, null)
  })
})

5.2 - Browsing Context

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

This section contains the APIs related to input commands.

Perform Actions

Selenium v4.17

        Actions selectThreeOptions =
                actions.click(options.get(1)).keyDown(Keys.SHIFT).click(options.get(3)).keyUp(Keys.SHIFT);

        input.perform(windowHandle, selectThreeOptions.getSequences());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Input;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.interactions.Actions;

class ActionsTest extends BaseTest {
    private Input input;

    private String windowHandle;

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        windowHandle = driver.getWindowHandle();
        input = new Input(driver);
    }

    @Test
    void canPerformInputActions() {
        driver.get("https://www.selenium.dev/selenium/web/formSelectionPage.html");

        List<WebElement> options = driver.findElements(By.tagName("option"));

        Actions actions = new Actions(driver);
        Actions selectThreeOptions =
                actions.click(options.get(1)).keyDown(Keys.SHIFT).click(options.get(3)).keyUp(Keys.SHIFT);

        input.perform(windowHandle, selectThreeOptions.getSequences());

        WebElement showButton = driver.findElement(By.name("showselected"));
        showButton.click();

        WebElement resultElement = driver.findElement(By.id("result"));
        Assertions.assertTrue(resultElement.getText().contains("roquefort parmigiano cheddar"));
        }

    @Test
    void canPerformReleaseAction() {
        driver.get("https://www.selenium.dev/selenium/web/bidi/release_action.html");

        WebElement inputTextBox = driver.findElement(By.id("keys"));

        Actions sendLowercase =
                new Actions(driver).keyDown(inputTextBox, "a").keyDown(inputTextBox, "b");

        input.perform(windowHandle, sendLowercase.getSequences());
        ((JavascriptExecutor) driver).executeScript("resetEvents()");

        input.release(windowHandle);

        List<Map<String, Object>> events =
                (List<Map<String, Object>>)
                        ((JavascriptExecutor) driver).executeScript("return allEvents.events");
        Assertions.assertEquals("KeyB", events.get(0).get("code"));
        Assertions.assertEquals("KeyA", events.get(1).get("code"));
        }
    }

Selenium v4.17

    const actions = driver.actions().click(options[1]).keyDown(Key.SHIFT).click(options[3]).keyUp(Key.SHIFT).getSequences()

    await input.perform(browsingContextId, actions)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, Key, Builder} = require("selenium-webdriver")
const Input = require('selenium-webdriver/bidi/input')

describe('Input module', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can perform input action', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const input = await Input(driver)
    await driver.get('https://www.selenium.dev/selenium/web/formSelectionPage.html')

    let options = await driver.findElements(By.tagName('option'))

    const actions = driver.actions().click(options[1]).keyDown(Key.SHIFT).click(options[3]).keyUp(Key.SHIFT).getSequences()

    await input.perform(browsingContextId, actions)

    let showButton = await driver.findElement(By.name('showselected'))
    showButton.click()

    let resultElement = await driver.findElement(By.id('result'))
    await resultElement.getText().then(function (text) {
      assert(text.includes('oquefort parmigiano cheddar'))
    })
  })

  it('can execute release in browsing context', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const input = await Input(driver)
    await driver.get('https://www.selenium.dev/selenium/web/bidi/release_action.html')

    let inputTextBox = await driver.findElement(By.id('keys'))

    await driver.executeScript('arguments[0].focus()', inputTextBox)

    const actions = driver.actions().keyDown('a').keyDown('b').getSequences()

    await input.perform(browsingContextId, actions)

    await driver.executeScript('resetEvents()')

    await input.release(browsingContextId)

    const events = await driver.executeScript('return allEvents.events')

    assert.strictEqual(events[0].code, 'KeyB')
    assert.strictEqual(events[1].code, 'KeyA')
  })
})

Release Actions

Selenium v4.17

        Actions sendLowercase =
                new Actions(driver).keyDown(inputTextBox, "a").keyDown(inputTextBox, "b");

        input.perform(windowHandle, sendLowercase.getSequences());
        ((JavascriptExecutor) driver).executeScript("resetEvents()");

        input.release(windowHandle);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Input;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.interactions.Actions;

class ActionsTest extends BaseTest {
    private Input input;

    private String windowHandle;

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        windowHandle = driver.getWindowHandle();
        input = new Input(driver);
    }

    @Test
    void canPerformInputActions() {
        driver.get("https://www.selenium.dev/selenium/web/formSelectionPage.html");

        List<WebElement> options = driver.findElements(By.tagName("option"));

        Actions actions = new Actions(driver);
        Actions selectThreeOptions =
                actions.click(options.get(1)).keyDown(Keys.SHIFT).click(options.get(3)).keyUp(Keys.SHIFT);

        input.perform(windowHandle, selectThreeOptions.getSequences());

        WebElement showButton = driver.findElement(By.name("showselected"));
        showButton.click();

        WebElement resultElement = driver.findElement(By.id("result"));
        Assertions.assertTrue(resultElement.getText().contains("roquefort parmigiano cheddar"));
        }

    @Test
    void canPerformReleaseAction() {
        driver.get("https://www.selenium.dev/selenium/web/bidi/release_action.html");

        WebElement inputTextBox = driver.findElement(By.id("keys"));

        Actions sendLowercase =
                new Actions(driver).keyDown(inputTextBox, "a").keyDown(inputTextBox, "b");

        input.perform(windowHandle, sendLowercase.getSequences());
        ((JavascriptExecutor) driver).executeScript("resetEvents()");

        input.release(windowHandle);

        List<Map<String, Object>> events =
                (List<Map<String, Object>>)
                        ((JavascriptExecutor) driver).executeScript("return allEvents.events");
        Assertions.assertEquals("KeyB", events.get(0).get("code"));
        Assertions.assertEquals("KeyA", events.get(1).get("code"));
        }
    }

Selenium v4.17

    await input.release(browsingContextId)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, Key, Builder} = require("selenium-webdriver")
const Input = require('selenium-webdriver/bidi/input')

describe('Input module', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can perform input action', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const input = await Input(driver)
    await driver.get('https://www.selenium.dev/selenium/web/formSelectionPage.html')

    let options = await driver.findElements(By.tagName('option'))

    const actions = driver.actions().click(options[1]).keyDown(Key.SHIFT).click(options[3]).keyUp(Key.SHIFT).getSequences()

    await input.perform(browsingContextId, actions)

    let showButton = await driver.findElement(By.name('showselected'))
    showButton.click()

    let resultElement = await driver.findElement(By.id('result'))
    await resultElement.getText().then(function (text) {
      assert(text.includes('oquefort parmigiano cheddar'))
    })
  })

  it('can execute release in browsing context', async function () {
    const browsingContextId = await driver.getWindowHandle()
    const input = await Input(driver)
    await driver.get('https://www.selenium.dev/selenium/web/bidi/release_action.html')

    let inputTextBox = await driver.findElement(By.id('keys'))

    await driver.executeScript('arguments[0].focus()', inputTextBox)

    const actions = driver.actions().keyDown('a').keyDown('b').getSequences()

    await input.perform(browsingContextId, actions)

    await driver.executeScript('resetEvents()')

    await input.release(browsingContextId)

    const events = await driver.executeScript('return allEvents.events')

    assert.strictEqual(events[0].code, 'KeyB')
    assert.strictEqual(events[1].code, 'KeyA')
  })
})

5.3 - Network

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

Commands

This section contains the APIs related to network commands.

Add network intercept

Selenium v4.18

        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Selenium v4.18

    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const Network = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");


describe('Network commands', function () {
  let driver
  let network


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()

    network = await Network(driver)
  })

  afterEach(async function () {
    await network.close()
    await driver.quit()
  })

  xit('can add intercept', async function () {
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)
  })

  xit('can remove intercept', async function () {
    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)

    await network.removeIntercept(intercept)
  })

  xit('can continue with auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
    await driver.get('https://the-internet.herokuapp.com/basic_auth')

    const successMessage = 'Congratulations! You must have the proper credentials.'

    let elementMessage = await driver.findElement(By.tagName('p')).getText()
    assert.equal(elementMessage, successMessage)
  })

  xit('can continue without auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    const alert = await driver.wait(until.alertIsPresent())
    await alert.dismiss()

    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })

  xit('can cancel auth ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })
})

Remove network intercept

Selenium v4.18

        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Selenium v4.18

    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const Network = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");


describe('Network commands', function () {
  let driver
  let network


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()

    network = await Network(driver)
  })

  afterEach(async function () {
    await network.close()
    await driver.quit()
  })

  xit('can add intercept', async function () {
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)
  })

  xit('can remove intercept', async function () {
    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)

    await network.removeIntercept(intercept)
  })

  xit('can continue with auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
    await driver.get('https://the-internet.herokuapp.com/basic_auth')

    const successMessage = 'Congratulations! You must have the proper credentials.'

    let elementMessage = await driver.findElement(By.tagName('p')).getText()
    assert.equal(elementMessage, successMessage)
  })

  xit('can continue without auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    const alert = await driver.wait(until.alertIsPresent())
    await alert.dismiss()

    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })

  xit('can cancel auth ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })
})

Continue request blocked at authRequired phase with credentials

Selenium v4.18

        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Selenium v4.18

    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const Network = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");


describe('Network commands', function () {
  let driver
  let network


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()

    network = await Network(driver)
  })

  afterEach(async function () {
    await network.close()
    await driver.quit()
  })

  xit('can add intercept', async function () {
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)
  })

  xit('can remove intercept', async function () {
    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)

    await network.removeIntercept(intercept)
  })

  xit('can continue with auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
    await driver.get('https://the-internet.herokuapp.com/basic_auth')

    const successMessage = 'Congratulations! You must have the proper credentials.'

    let elementMessage = await driver.findElement(By.tagName('p')).getText()
    assert.equal(elementMessage, successMessage)
  })

  xit('can continue without auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    const alert = await driver.wait(until.alertIsPresent())
    await alert.dismiss()

    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })

  xit('can cancel auth ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })
})

Continue request blocked at authRequired phase without credentials

Selenium v4.18

        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Selenium v4.18

    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const Network = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");


describe('Network commands', function () {
  let driver
  let network


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()

    network = await Network(driver)
  })

  afterEach(async function () {
    await network.close()
    await driver.quit()
  })

  xit('can add intercept', async function () {
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)
  })

  xit('can remove intercept', async function () {
    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)

    await network.removeIntercept(intercept)
  })

  xit('can continue with auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
    await driver.get('https://the-internet.herokuapp.com/basic_auth')

    const successMessage = 'Congratulations! You must have the proper credentials.'

    let elementMessage = await driver.findElement(By.tagName('p')).getText()
    assert.equal(elementMessage, successMessage)
  })

  xit('can continue without auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    const alert = await driver.wait(until.alertIsPresent())
    await alert.dismiss()

    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })

  xit('can cancel auth ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })
})

Cancel request blocked at authRequired phase

Selenium v4.18

        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Selenium v4.18

    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const Network = require('selenium-webdriver/bidi/network')
const {until, By, Builder} = require('selenium-webdriver')
const {AddInterceptParameters} = require("selenium-webdriver/bidi/addInterceptParameters");
const {InterceptPhase} = require("selenium-webdriver/bidi/interceptPhase");


describe('Network commands', function () {
  let driver
  let network


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()

    network = await Network(driver)
  })

  afterEach(async function () {
    await network.close()
    await driver.quit()
  })

  xit('can add intercept', async function () {
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)
  })

  xit('can remove intercept', async function () {
    const network = await Network(driver)
    const intercept = await network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT))
    assert.notEqual(intercept, null)

    await network.removeIntercept(intercept)
  })

  xit('can continue with auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuth(event.request.request, 'admin','admin')
    })
    await driver.get('https://the-internet.herokuapp.com/basic_auth')

    const successMessage = 'Congratulations! You must have the proper credentials.'

    let elementMessage = await driver.findElement(By.tagName('p')).getText()
    assert.equal(elementMessage, successMessage)
  })

  xit('can continue without auth credentials ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.continueWithAuthNoCredentials(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    const alert = await driver.wait(until.alertIsPresent())
    await alert.dismiss()

    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })

  xit('can cancel auth ', async function () {
    await network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))

    await network.authRequired(async (event) => {
      await network.cancelAuth(event.request.request)
    })

    await driver.get('https://the-internet.herokuapp.com/basic_auth')
    let source = await driver.getPageSource()
    assert.equal(source.includes('Not authorized'), true)
  })
})

Fail request

Selenium v4.18

        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.UsernameAndPassword;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.AddInterceptParameters;
import org.openqa.selenium.bidi.network.InterceptPhase;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

class NetworkCommandsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
        wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    @Test
    @Disabled
    void canAddIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
        }
    }

    @Test
    @Disabled
    void canRemoveIntercept() {
        try (Network network = new Network(driver)) {
            String intercept =
                    network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            Assertions.assertNotNull(intercept);
            network.removeIntercept(intercept);
        }
    }

    @Test
    @Disabled
    void canContinueWithAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            network.continueWithAuth(
                                    responseDetails.getRequest().getRequestId(),
                                    new UsernameAndPassword("admin", "admin")));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            String successMessage = "Congratulations! You must have the proper credentials.";
            WebElement elementMessage = driver.findElement(By.tagName("p"));
            Assertions.assertEquals(successMessage, elementMessage.getText());
        }
    }

    @Test
    @Disabled
    void canContinueWithoutAuthCredentials() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.continueWithAuthNoCredentials(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Alert alert = wait.until(ExpectedConditions.alertIsPresent());
            alert.dismiss();
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canCancelAuth() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED));
            network.onAuthRequired(
                    responseDetails ->
                            // Does not handle the alert
                            network.cancelAuth(responseDetails.getRequest().getRequestId()));
            driver.get("https://the-internet.herokuapp.com/basic_auth");
            Assertions.assertTrue(driver.getPageSource().contains("Not authorized"));
        }
    }

    @Test
    @Disabled
    void canFailRequest() {
        try (Network network = new Network(driver)) {
            network.addIntercept(new AddInterceptParameters(InterceptPhase.BEFORE_REQUEST_SENT));
            network.onBeforeRequestSent(
                    responseDetails -> network.failRequest(responseDetails.getRequest().getRequestId()));
            driver.manage().timeouts().pageLoadTimeout(Duration.of(5, ChronoUnit.SECONDS));
            Assertions.assertThrows(TimeoutException.class, () -> driver.get("https://the-internet.herokuapp.com/basic_auth"));
            }
    }
}

Events

This section contains the APIs related to network events.

Before Request Sent

Selenium v4.15

        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
            network.onBeforeRequestSent(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.bidi.network.ResponseDetails;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class NetworkEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToBeforeRequestSentEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
            network.onBeforeRequestSent(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
        }
    }

    @Test
    void canListenToResponseStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseStarted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseCompleted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEventWithCookie()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();

            driver.get("https://www.selenium.dev/selenium/web/blankPage");
            driver.manage().addCookie(new Cookie("foo", "bar"));
            network.onBeforeRequestSent(future::complete);
            driver.navigate().refresh();

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());

            Assertions.assertEquals("foo", requestSent.getRequest().getCookies().get(0).getName());
            Assertions.assertEquals("bar", requestSent.getRequest().getCookies().get(0).getValue().getValue());
        }
    }

    @Test
    void canListenToOnAuthRequiredEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onAuthRequired(future::complete);
            driver.get("https://the-internet.herokuapp.com/basic_auth");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(401L, response.getResponseData().getStatus());
        }
    }
}

Selenium v4.18

    let beforeRequestEvent = null
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')
Show full example
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const { Network } = require("selenium-webdriver/bidi/network");
const {until, Builder} = require("selenium-webdriver");


describe('Network events', function () {
  let driver


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to event before request is sent', async function () {
    let beforeRequestEvent = null
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')

    assert.equal(beforeRequestEvent.request.method, 'GET')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())
  })

  it('can request cookies', async function () {
    const network = await Network(driver)
    let beforeRequestEvent = null
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')
    await driver.manage().addCookie({
      name: 'north',
      value: 'biryani',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.method, 'GET')
    assert.equal(beforeRequestEvent.request.cookies[0].name, 'north')
    assert.equal(beforeRequestEvent.request.cookies[0].value.value, 'biryani')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())

    await driver.manage().addCookie({
      name: 'south',
      value: 'dosa',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.cookies[1].name, 'south')
    assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa')
  })

  it('can redirect http equiv', async function () {
    let beforeRequestEvent = []
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent.push(event)
    })

    await driver.get('http://www.selenium.dev/selenium/web/bidi/redirected_http_equiv.html')
    await driver.wait(until.urlContains('redirected.html'), 1000)

    assert.equal(beforeRequestEvent[0].request.method, 'GET')
    assert(beforeRequestEvent[0].request.url.includes('redirected_http_equiv.html'))
    assert.equal(beforeRequestEvent[2].request.method, 'GET')
    assert(beforeRequestEvent[3].request.url.includes('redirected.html'))
  })

  it('can subscribe to response started', async function () {
    let onResponseStarted = []
    const network = await Network(driver)
    await network.responseStarted(function (event) {
      onResponseStarted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseStarted[0].request.method, 'GET')
    assert.equal(onResponseStarted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseStarted[0].response.url, await driver.getCurrentUrl())
  })

  it('can subscribe to response completed', async function () {
    let onResponseCompleted = []
    const network = await Network(driver)
    await network.responseCompleted(function (event) {
      onResponseCompleted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseCompleted[0].request.method, 'GET')
    assert.equal(onResponseCompleted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseCompleted[0].response.fromCache, false)
    assert.equal(onResponseCompleted[0].response.status, 200)
  })
})

Response Started

Selenium v4.15

        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseStarted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.bidi.network.ResponseDetails;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class NetworkEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToBeforeRequestSentEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
            network.onBeforeRequestSent(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
        }
    }

    @Test
    void canListenToResponseStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseStarted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseCompleted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEventWithCookie()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();

            driver.get("https://www.selenium.dev/selenium/web/blankPage");
            driver.manage().addCookie(new Cookie("foo", "bar"));
            network.onBeforeRequestSent(future::complete);
            driver.navigate().refresh();

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());

            Assertions.assertEquals("foo", requestSent.getRequest().getCookies().get(0).getName());
            Assertions.assertEquals("bar", requestSent.getRequest().getCookies().get(0).getValue().getValue());
        }
    }

    @Test
    void canListenToOnAuthRequiredEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onAuthRequired(future::complete);
            driver.get("https://the-internet.herokuapp.com/basic_auth");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(401L, response.getResponseData().getStatus());
        }
    }
}

Selenium v4.18

    let onResponseStarted = []
    const network = await Network(driver)
    await network.responseStarted(function (event) {
      onResponseStarted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
Show full example
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const { Network } = require("selenium-webdriver/bidi/network");
const {until, Builder} = require("selenium-webdriver");


describe('Network events', function () {
  let driver


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to event before request is sent', async function () {
    let beforeRequestEvent = null
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')

    assert.equal(beforeRequestEvent.request.method, 'GET')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())
  })

  it('can request cookies', async function () {
    const network = await Network(driver)
    let beforeRequestEvent = null
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')
    await driver.manage().addCookie({
      name: 'north',
      value: 'biryani',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.method, 'GET')
    assert.equal(beforeRequestEvent.request.cookies[0].name, 'north')
    assert.equal(beforeRequestEvent.request.cookies[0].value.value, 'biryani')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())

    await driver.manage().addCookie({
      name: 'south',
      value: 'dosa',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.cookies[1].name, 'south')
    assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa')
  })

  it('can redirect http equiv', async function () {
    let beforeRequestEvent = []
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent.push(event)
    })

    await driver.get('http://www.selenium.dev/selenium/web/bidi/redirected_http_equiv.html')
    await driver.wait(until.urlContains('redirected.html'), 1000)

    assert.equal(beforeRequestEvent[0].request.method, 'GET')
    assert(beforeRequestEvent[0].request.url.includes('redirected_http_equiv.html'))
    assert.equal(beforeRequestEvent[2].request.method, 'GET')
    assert(beforeRequestEvent[3].request.url.includes('redirected.html'))
  })

  it('can subscribe to response started', async function () {
    let onResponseStarted = []
    const network = await Network(driver)
    await network.responseStarted(function (event) {
      onResponseStarted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseStarted[0].request.method, 'GET')
    assert.equal(onResponseStarted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseStarted[0].response.url, await driver.getCurrentUrl())
  })

  it('can subscribe to response completed', async function () {
    let onResponseCompleted = []
    const network = await Network(driver)
    await network.responseCompleted(function (event) {
      onResponseCompleted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseCompleted[0].request.method, 'GET')
    assert.equal(onResponseCompleted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseCompleted[0].response.fromCache, false)
    assert.equal(onResponseCompleted[0].response.status, 200)
  })
})

Response Completed

Selenium v4.15

        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseCompleted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.bidi.network.ResponseDetails;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class NetworkEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToBeforeRequestSentEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
            network.onBeforeRequestSent(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
        }
    }

    @Test
    void canListenToResponseStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseStarted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseCompleted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEventWithCookie()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();

            driver.get("https://www.selenium.dev/selenium/web/blankPage");
            driver.manage().addCookie(new Cookie("foo", "bar"));
            network.onBeforeRequestSent(future::complete);
            driver.navigate().refresh();

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());

            Assertions.assertEquals("foo", requestSent.getRequest().getCookies().get(0).getName());
            Assertions.assertEquals("bar", requestSent.getRequest().getCookies().get(0).getValue().getValue());
        }
    }

    @Test
    void canListenToOnAuthRequiredEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onAuthRequired(future::complete);
            driver.get("https://the-internet.herokuapp.com/basic_auth");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(401L, response.getResponseData().getStatus());
        }
    }
}

Selenium v4.18

    let onResponseCompleted = []
    const network = await Network(driver)
    await network.responseCompleted(function (event) {
      onResponseCompleted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
Show full example
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const { Network } = require("selenium-webdriver/bidi/network");
const {until, Builder} = require("selenium-webdriver");


describe('Network events', function () {
  let driver


  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to event before request is sent', async function () {
    let beforeRequestEvent = null
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')

    assert.equal(beforeRequestEvent.request.method, 'GET')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())
  })

  it('can request cookies', async function () {
    const network = await Network(driver)
    let beforeRequestEvent = null
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent = event
    })

    await driver.get('https://www.selenium.dev/selenium/web/blank.html')
    await driver.manage().addCookie({
      name: 'north',
      value: 'biryani',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.method, 'GET')
    assert.equal(beforeRequestEvent.request.cookies[0].name, 'north')
    assert.equal(beforeRequestEvent.request.cookies[0].value.value, 'biryani')
    const url = beforeRequestEvent.request.url
    assert.equal(url, await driver.getCurrentUrl())

    await driver.manage().addCookie({
      name: 'south',
      value: 'dosa',
    })
    await driver.navigate().refresh()

    assert.equal(beforeRequestEvent.request.cookies[1].name, 'south')
    assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa')
  })

  it('can redirect http equiv', async function () {
    let beforeRequestEvent = []
    const network = await Network(driver)
    await network.beforeRequestSent(function (event) {
      beforeRequestEvent.push(event)
    })

    await driver.get('http://www.selenium.dev/selenium/web/bidi/redirected_http_equiv.html')
    await driver.wait(until.urlContains('redirected.html'), 1000)

    assert.equal(beforeRequestEvent[0].request.method, 'GET')
    assert(beforeRequestEvent[0].request.url.includes('redirected_http_equiv.html'))
    assert.equal(beforeRequestEvent[2].request.method, 'GET')
    assert(beforeRequestEvent[3].request.url.includes('redirected.html'))
  })

  it('can subscribe to response started', async function () {
    let onResponseStarted = []
    const network = await Network(driver)
    await network.responseStarted(function (event) {
      onResponseStarted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseStarted[0].request.method, 'GET')
    assert.equal(onResponseStarted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseStarted[0].response.url, await driver.getCurrentUrl())
  })

  it('can subscribe to response completed', async function () {
    let onResponseCompleted = []
    const network = await Network(driver)
    await network.responseCompleted(function (event) {
      onResponseCompleted.push(event)
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')

    assert.equal(onResponseCompleted[0].request.method, 'GET')
    assert.equal(onResponseCompleted[0].request.url, await driver.getCurrentUrl())
    assert.equal(onResponseCompleted[0].response.fromCache, false)
    assert.equal(onResponseCompleted[0].response.status, 200)
  })
})

Auth Required

Selenium v4.17

        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onAuthRequired(future::complete);
            driver.get("https://the-internet.herokuapp.com/basic_auth");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.bidi.module.Network;
import org.openqa.selenium.bidi.network.BeforeRequestSent;
import org.openqa.selenium.bidi.network.ResponseDetails;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class NetworkEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canListenToBeforeRequestSentEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();
            network.onBeforeRequestSent(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());
        }
    }

    @Test
    void canListenToResponseStartedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseStarted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onResponseCompleted(future::complete);
            driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(200L, response.getResponseData().getStatus());
        }
    }

    @Test
    void canListenToResponseCompletedEventWithCookie()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<BeforeRequestSent> future = new CompletableFuture<>();

            driver.get("https://www.selenium.dev/selenium/web/blankPage");
            driver.manage().addCookie(new Cookie("foo", "bar"));
            network.onBeforeRequestSent(future::complete);
            driver.navigate().refresh();

            BeforeRequestSent requestSent = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();

            Assertions.assertEquals(windowHandle, requestSent.getBrowsingContextId());
            Assertions.assertEquals("get", requestSent.getRequest().getMethod().toLowerCase());

            Assertions.assertEquals("foo", requestSent.getRequest().getCookies().get(0).getName());
            Assertions.assertEquals("bar", requestSent.getRequest().getCookies().get(0).getValue().getValue());
        }
    }

    @Test
    void canListenToOnAuthRequiredEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Network network = new Network(driver)) {
            CompletableFuture<ResponseDetails> future = new CompletableFuture<>();
            network.onAuthRequired(future::complete);
            driver.get("https://the-internet.herokuapp.com/basic_auth");

            ResponseDetails response = future.get(5, TimeUnit.SECONDS);
            String windowHandle = driver.getWindowHandle();
            Assertions.assertEquals(windowHandle, response.getBrowsingContextId());
            Assertions.assertEquals("get", response.getRequest().getMethod().toLowerCase());
            Assertions.assertEquals(401L, response.getResponseData().getStatus());
        }
    }
}

5.4 - Script

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

Commands

This section contains the APIs related to script commands.

Call function in a browsing context

Selenium v4.15

        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Call function in a sandbox

Selenium v4.15

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Call function in a realm

Selenium v4.15

        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Evaluate script in a browsing context

Selenium v4.15

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Evaluate script in a sandbox

Selenium v4.15

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Evaluate script in a realm

Selenium v4.15

        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Disown handles in a browsing context

Selenium v4.15

            script.disownBrowsingContextScript(
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    await manager.disownBrowsingContextScript(id, boxId)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Disown handles in a realm

Selenium v4.15

            script.disownRealmScript(realmId, List.of(boxId));
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    await manager.disownRealmScript(realmId, boxId)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Get all realms

Selenium v4.15

        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Get realm by type

Selenium v4.15

        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Get browsing context realms

Selenium v4.15

        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Get browsing context realms by type

Selenium v4.15

            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.9

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Preload a script

Selenium v4.15

            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.10

    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Remove a preloaded script

Selenium v4.15

                script.removePreloadScript(id);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WindowType;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.browsingcontext.ReadinessState;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.script.ChannelValue;
import org.openqa.selenium.bidi.script.EvaluateResult;
import org.openqa.selenium.bidi.script.EvaluateResultExceptionValue;
import org.openqa.selenium.bidi.script.EvaluateResultSuccess;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.ObjectLocalValue;
import org.openqa.selenium.bidi.script.PrimitiveProtocolValue;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.bidi.script.RemoteReference;
import org.openqa.selenium.bidi.script.ResultOwnership;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void canCallFunction() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            arguments.add(PrimitiveProtocolValue.numberValue(22));

            Map<Object, LocalValue> value = new HashMap<>();
            value.put("some_property", LocalValue.numberValue(42));
            LocalValue thisParameter = LocalValue.objectValue(value);

            arguments.add(thisParameter);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "function processWithPromise(argument) {\n"
                                    + "  return new Promise((resolve, reject) => {\n"
                                    + "    setTimeout(() => {\n"
                                    + "      resolve(argument + this.some_property);\n"
                                    + "    }, 1000)\n"
                                    + "  })\n"
                                    + "}",
                            true,
                            Optional.of(arguments),
                            Optional.of(thisParameter),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(64L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithDeclaration() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id, "()=>{return 1+2;}", false, Optional.empty(), Optional.empty(), Optional.empty());
            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithArguments() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            List<LocalValue> arguments = new ArrayList<>();
            LocalValue value1 = PrimitiveProtocolValue.stringValue("ARGUMENT_STRING_VALUE");
            LocalValue value2 = PrimitiveProtocolValue.numberValue(42);
            arguments.add(value1);
            arguments.add(value2);

            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "(...args)=>{return args}",
                            false,
                            Optional.of(arguments),
                            Optional.empty(),
                            Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(2, ((List<Object>) successResult.getResult().getValue().get()).size());
        }
    }

    @Test
    void canCallFunctionWithAwaitPromise() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "async function() {{\n"
                                + "            await new Promise(r => setTimeout(() => r(), 0));\n"
                                + "            return \"SOME_DELAYED_RESULT\";\n"
                                + "          }}",
                        true,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("SOME_DELAYED_RESULT", (String) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithThisParameter() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        Map<Object, LocalValue> value = new HashMap<>();
        value.put("some_property", PrimitiveProtocolValue.numberValue(42));
        LocalValue thisParameter = LocalValue.objectValue(value);

        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "function(){return this.some_property}",
                        false,
                        Optional.empty(),
                        Optional.of(thisParameter),
                        Optional.empty());

        EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
        Assertions.assertEquals("number", successResult.getResult().getType());
        Assertions.assertEquals(42L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canCallFunctionWithOwnershipRoot() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "async function(){return {a:1}}",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
            }
        }

    @Test
    void canCallFunctionThatThrowsException() {
        String id = driver.getWindowHandle();
    try (Script script = new Script(id, driver)) {
        EvaluateResult result =
                script.callFunctionInBrowsingContext(
                        id,
                        "))) !!@@## some invalid JS script (((",
                        false,
                        Optional.empty(),
                        Optional.empty(),
                        Optional.empty());
        EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
        Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
        Assertions.assertEquals(
                "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canCallFunctionInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.callFunctionInBrowsingContext(
                            id,
                            "sandbox",
                            "() => window.foo",
                            true,
                            Optional.empty(),
                            Optional.empty(),
                            Optional.empty());

        Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canCallFunctionInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result = script.callFunctionInRealm(
                    realmId,
                    "() => { window.foo = 3; }",
                    true,
                    Optional.empty(),
                    Optional.empty(),
                    Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateScript() {
        String id = driver.getWindowHandle();

        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(id, "1 + 2", true, Optional.empty());

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
            Assertions.assertEquals(3L, (Long) successResult.getResult().getValue().get());
        }
    }

    @Test
    void canEvaluateScriptThatThrowsException() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "))) !!@@## some invalid JS script (((", false, Optional.empty());

            EvaluateResultExceptionValue exception = (EvaluateResultExceptionValue) result;
            Assertions.assertEquals("error", exception.getExceptionDetails().getException().getType());
            Assertions.assertEquals(
                    "SyntaxError: expected expression, got ')'", exception.getExceptionDetails().getText());
        }
    }

    @Test
    void canEvaluateScriptWithResulWithOwnership() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "Promise.resolve({a:1})", true, Optional.of(ResultOwnership.ROOT));

            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            id, "sandbox", "window.foo", true, Optional.empty());


            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canEvaluateInARealm() {
        String tab = driver.getWindowHandle();
        try (Script script = new Script(tab, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            EvaluateResult result =
                    script.evaluateFunctionInRealm(
                            realmId, "window.foo", true, Optional.empty());

            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canDisownHandle() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            script.disownBrowsingContextScript(
                            window, List.of(boxId));

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canDisownHandleInARealm() {
        String window = driver.getWindowHandle();
        try (Script script = new Script(window, driver)) {
            BrowsingContext context = new BrowsingContext(driver, window);

            context.navigate("https://www.selenium.dev/selenium/web/dynamic.html", ReadinessState.COMPLETE);

            driver.findElement(By.id("adder")).click();

            getLocatedElement(driver, By.id("box0"));

            List<RealmInfo> realms = script.getAllRealms();
            String realmId = realms.get(0).getRealmId();

            // Retrieve the handle for the element added to DOM
            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            window, "document.querySelector('.redbox');", false, Optional.of(ResultOwnership.ROOT));
            String boxId = ((EvaluateResultSuccess)result).getResult().getHandle().get();

            LocalValue value =
                    LocalValue.remoteReference(
                            RemoteReference.Type.HANDLE, boxId);

            EvaluateResult checkHandle = script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty());

            // The handle is present in memory, else it would result in exception
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, checkHandle.getResultType());

            // Useful to memory management in a dynamic webpage where DOM mutations happen often
            script.disownRealmScript(realmId, List.of(boxId));

            // Since the handle is now eligible for garbage collections, it is no longer available to be used.
            Assertions.assertThrows(WebDriverException.class, () -> script.callFunctionInBrowsingContext(
                    window,
                    "arg => arg.a",
                    false, Optional.of(List.of(value)),
                    Optional.empty(),
                    Optional.empty()));
        }
    }

    @Test
    void canGetAllRealms() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getAllRealms();
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmByType() {
        String firstWindow = driver.getWindowHandle();
        String secondWindow = driver.switchTo().newWindow(WindowType.WINDOW).getWindowHandle();
        try (Script script = new Script(firstWindow, driver)) {
            List<RealmInfo> realms = script.getRealmsByType(RealmType.WINDOW);
            Assertions.assertEquals(2, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContext() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> realms = script.getRealmsInBrowsingContext(tabId);
            Assertions.assertEquals(1, realms.size());
        }
    }

    @Test
    void canGetRealmInBrowsingContextByType() {
        String windowId = driver.getWindowHandle();
        String tabId = driver.switchTo().newWindow(WindowType.TAB).getWindowHandle();
        try (Script script = new Script(windowId, driver)) {
            List<RealmInfo> windowRealms =
                    script.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW);
            Assertions.assertEquals(1, windowRealms.size());
        }
    }

    @Test
    void canAddPreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

                Assertions.assertEquals("{preload_script_console_text}", logEntry.getText());
            }
        }
    }

    @Test
    void canAddPreloadScriptWithArguments() {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript(
                            "(channel) => channel('will_be_send', 'will_be_ignored')",
                            List.of(new ChannelValue("channel_name")));
            Assertions.assertNotNull(id);
        }
    }

    @Test
    void canAddPreloadScriptInASandbox() {
        try (Script script = new Script(driver)) {
            String id = script.addPreloadScript("() => { window.bar=2; }", "sandbox");
            Assertions.assertNotNull(id);
            driver.get("https://www.selenium.dev/selenium/blankPage");

            EvaluateResult result =
                    script.evaluateFunctionInBrowsingContext(
                            driver.getWindowHandle(), "sandbox", "window.bar", true, Optional.empty());
            Assertions.assertEquals(EvaluateResult.Type.SUCCESS, result.getResultType());
        }
    }

    @Test
    void canRemovePreloadScript() throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            String id =
                    script.addPreloadScript("() => {{ console.log('{preload_script_console_text}') }}");

            Assertions.assertNotNull(id);

            try (LogInspector logInspector = new LogInspector(driver)) {
                CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
                logInspector.onConsoleEntry(future::complete);

                script.removePreloadScript(id);

                driver.get("https://www.selenium.dev/selenium/blankPage");

                Assertions.assertThrows(TimeoutException.class, () -> future.get(5, TimeUnit.SECONDS));
            }
        }
    }
}

Selenium v4.10

    await manager.removePreloadScript(scriptId)
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {By, until, Builder} = require("selenium-webdriver")
const ScriptManager = require('selenium-webdriver/bidi/scriptManager')
const {ResultOwnership} = require("selenium-webdriver/bidi/resultOwnership");
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue");
const {LocalValue, RemoteReferenceType, ReferenceValue} = require("selenium-webdriver/bidi/protocolValue");
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");
const BrowsingContext = require("selenium-webdriver/bidi/browsingContext");
const {WebDriverError} = require("selenium-webdriver/lib/error");
const {RealmType} = require("selenium-webdriver/bidi/realmInfo");
const LogInspector = require("selenium-webdriver/bidi/logInspector");



describe('Script commands', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can call function', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createNumberValue(22))
    argumentValues.push(value)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function processWithPromise(argument) {' +
      'return new Promise((resolve, reject) => {' +
      'setTimeout(() => {' +
      'resolve(argument + this.some_property);' +
      '}, 1000)' +
      '})' +
      '}',
      true,
      argumentValues,
      thisParameter,
      ResultOwnership.ROOT)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 64)
  })

  it('can call function with declaration', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '()=>{return 1+2;}', false)
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can call function to get element', async function () {
    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded')
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '() => document.getElementById("consoleLog")',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.type, 'node')
    assert.notEqual(result.result.value, null)
    assert.notEqual(result.result.value.nodeType, null)
  })

  it('can call function with arguments', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let argumentValues = []
    let value1 = new ArgumentValue(LocalValue.createStringValue('ARGUMENT_STRING_VALUE'))
    let value2 = new ArgumentValue(LocalValue.createNumberValue(42))
    argumentValues.push(value1)
    argumentValues.push(value2)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      '(...args)=>{return args}',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value.length, 2)
  })

  it('can call function with await promise', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      true,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 'SOME_DELAYED_RESULT')
  })

  it('can call function with await promise false', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function() {{\n' +
      '            await new Promise(r => setTimeout(() => r(), 0));\n' +
      '            return "SOME_DELAYED_RESULT";\n' +
      '          }}',
      false,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.type, 'promise')
  })

  it('can call function with this parameter', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    let mapValue = {some_property: LocalValue.createNumberValue(42)}
    let thisParameter = new ArgumentValue(LocalValue.createObjectValue(mapValue)).asMap()

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'function(){return this.some_property}',
      false,
      null,
      thisParameter,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 42)
  })

  it('can call function with ownership root', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.ROOT,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function with ownership none', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(
      id,
      'async function(){return {a:1}}',
      true,
      null,
      null,
      ResultOwnership.NONE,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.realmId, null)
    assert.equal(result.result.handle, undefined)
    assert.notEqual(result.result.value, null)
  })

  it('can call function that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.callFunctionInBrowsingContext(id, '))) !!@@## some invalid JS script (((', false)
    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)

    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can call function in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.callFunctionInBrowsingContext(id, '() => { window.foo = 2; }', true, null, null, null, 'sandbox')

    const resultInSandbox = await manager.callFunctionInBrowsingContext(
      id,
      '() => window.foo',
      true,
      null,
      null,
      null,
      'sandbox',
    )

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
  })

  it('can call function in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.callFunctionInRealm(realmId, '() => { window.foo = 3; }', true)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(id, '1 + 2', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can evaluate script that throws exception', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      '))) !!@@## some invalid JS script (((',
      false,
    )

    assert.equal(result.resultType, EvaluateResultType.EXCEPTION)
    assert.equal(result.exceptionDetails.exception.type, 'error')
    assert.equal(result.exceptionDetails.text, "SyntaxError: expected expression, got ')'")
    assert.equal(result.exceptionDetails.columnNumber, 39)
    assert.equal(result.exceptionDetails.stackTrace.callFrames.length, 0)
  })

  it('can evaluate script with result ownership', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const result = await manager.evaluateFunctionInBrowsingContext(
      id,
      'Promise.resolve({a:1})',
      true,
      ResultOwnership.ROOT,
    )

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(result.result.handle, null)
  })

  it('can evaluate in a sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.evaluateFunctionInBrowsingContext(id, 'window.foo = 2', true, null, 'sandbox')

    const resultInSandbox = await manager.evaluateFunctionInBrowsingContext(id, 'window.foo', true, null, 'sandbox')

    assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS)
    assert.equal(resultInSandbox.result.value, 2)
  })

  it('can evaluate in a realm', async function () {
    const firstTab = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(firstTab, driver)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    await manager.evaluateFunctionInRealm(realmId, 'window.foo = 3', true)

    const result = await manager.evaluateFunctionInRealm(realmId, 'window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

  it('can disown handles', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    await manager.disownBrowsingContextScript(id, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can disown handles in realm', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const browsingContext = await BrowsingContext(driver, {browsingContextId: id})

    const info = await browsingContext.navigate(
      'https://www.selenium.dev/selenium/web/dynamic.html',
      'complete'
    )

    await driver.findElement(By.id('adder')).click()

    await driver.wait(until.elementLocated(By.id('box0')), 10000)

    const realms = await manager.getAllRealms()
    const realmId = realms[0].realmId

    const evaluateResult = await manager.evaluateFunctionInBrowsingContext(
      id,
      "document.querySelector('.redbox');",
      false,
      ResultOwnership.ROOT,
    )

    assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS)
    let boxId = evaluateResult.result.handle

    let argumentValues = []
    let value1 = new ArgumentValue(new ReferenceValue(RemoteReferenceType.HANDLE, boxId))
    argumentValues.push(value1)
    let checkHandle = await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false, argumentValues)

    assert.equal(checkHandle.resultType, EvaluateResultType.SUCCESS)

    await manager.disownRealmScript(realmId, boxId)

    await manager.callFunctionInBrowsingContext(id, 'arg => arg.a', false).catch((error) => {
      assert(error instanceof WebDriverError)
    })
  })

  it('can get all realms', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getAllRealms()
    assert.equal(realms.length, 2)
  })

  it('can get realm by type', async function () {
    const firstWindow = await driver.getWindowHandle()
    await driver.switchTo().newWindow('window')
    const secondWindow = await driver.getWindowHandle()
    const manager = await ScriptManager(firstWindow, driver)

    const realms = await manager.getRealmsByType(RealmType.WINDOW)
    assert.equal(realms.length, 2)
  })

  it('can get realm in browsing context', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const tabId = await driver.getWindowHandle()
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContext(tabId)

    const tabRealm = realms[0]
    assert.equal(tabRealm.realmType, RealmType.WINDOW)
  })

  it('can get realm in browsing context by type', async function () {
    const windowId = await driver.getWindowHandle()
    await driver.switchTo().newWindow('tab')
    const manager = await ScriptManager(windowId, driver)

    const realms = await manager.getRealmsInBrowsingContextByType(windowId, RealmType.WINDOW)

    const windowRealm = realms[0]
    assert.equal(windowRealm.realmType, RealmType.WINDOW)
  })

  it('can add preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry.text, '{preload_script_console_text}')
  })

  it('can add preload script to sandbox', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    await manager.addPreloadScript('() => { window.bar = 2; }', undefined, 'sandbox')

    await driver.get('https://www.selenium.dev/selenium/blank')

    let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext(
      id,
      'window.bar',
      true,
      null,
      'sandbox',
    )

    assert.equal(result_in_sandbox.result.type, 'number')
    assert.equal(result_in_sandbox.result.value, 2)
  })

  it('can remove preload script', async function () {
    const id = await driver.getWindowHandle()
    const manager = await ScriptManager(id, driver)

    const scriptId = await manager.addPreloadScript('() => {{ console.log(\'{preload_script_console_text}\') }}')

    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await manager.removePreloadScript(scriptId)

    await driver.get('https://www.selenium.dev/selenium/blank')

    assert.equal(logEntry, null)
  })
})

Events

This section contains the APIs related to script events.

Message

Selenium v4.16

        try (Script script = new Script(driver)) {
            CompletableFuture<Message> future = new CompletableFuture<>();
            script.onMessage(future::complete);

            script.callFunctionInBrowsingContext(
                    driver.getWindowHandle(),
                    "(channel) => channel('foo')",
                    false,
                    Optional.of(List.of(LocalValue.channelValue("channel_name"))),
                    Optional.empty(),
                    Optional.empty());

            Message message = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals("channel_name", message.getChannel());
        }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.Message;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }
    
    @Test
    void canListenToChannelMessage()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<Message> future = new CompletableFuture<>();
            script.onMessage(future::complete);

            script.callFunctionInBrowsingContext(
                    driver.getWindowHandle(),
                    "(channel) => channel('foo')",
                    false,
                    Optional.of(List.of(LocalValue.channelValue("channel_name"))),
                    Optional.empty(),
                    Optional.empty());

            Message message = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals("channel_name", message.getChannel());
        }
    }

    @Test
    @DisabledOnOs(value = OS.MAC, disabledReason = "Works locally, times out on CI")
    void canListenToRealmCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmCreated(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.navigate("https://www.selenium.dev/selenium/blankPage");
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }

    @Test
    @Disabled
    void canListenToRealmDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmDestroyed(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.close();
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }
}

Selenium v4.18

    const manager = await ScriptManager(undefined, driver)

    let message = null

    await manager.onMessage((m) => {
      message = m
    })

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createChannelValue(new ChannelValue('channel_name')))
    argumentValues.push(value)

    const result = await manager.callFunctionInBrowsingContext(
      await driver.getWindowHandle(),
      '(channel) => channel("foo")',
      false,
      argumentValues,
    )
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {ScriptManager, BrowsingContext, Builder} = require("selenium-webdriver")
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue")
const {RealmType} = require("selenium-webdriver/bidi/realmInfo")
const {LocalValue, ChannelValue} = require("selenium-webdriver/bidi/protocolValue")
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");



describe('Script events', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to channel message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let message = null

    await manager.onMessage((m) => {
      message = m
    })

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createChannelValue(new ChannelValue('channel_name')))
    argumentValues.push(value)

    const result = await manager.callFunctionInBrowsingContext(
      await driver.getWindowHandle(),
      '(channel) => channel("foo")',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(message, null)
    assert.equal(message.channel, 'channel_name')
    assert.equal(message.data.type, 'string')
    assert.equal(message.data.value, 'foo')
  })

  it('can listen to realm created message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmCreated((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/blank', 'complete')

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })

  xit('can listen to realm destroyed message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmDestroyed((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.close()

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })
})

Realm Created

Selenium v4.16

        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmCreated(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.navigate("https://www.selenium.dev/selenium/blankPage");
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.Message;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }
    
    @Test
    void canListenToChannelMessage()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<Message> future = new CompletableFuture<>();
            script.onMessage(future::complete);

            script.callFunctionInBrowsingContext(
                    driver.getWindowHandle(),
                    "(channel) => channel('foo')",
                    false,
                    Optional.of(List.of(LocalValue.channelValue("channel_name"))),
                    Optional.empty(),
                    Optional.empty());

            Message message = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals("channel_name", message.getChannel());
        }
    }

    @Test
    @DisabledOnOs(value = OS.MAC, disabledReason = "Works locally, times out on CI")
    void canListenToRealmCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmCreated(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.navigate("https://www.selenium.dev/selenium/blankPage");
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }

    @Test
    @Disabled
    void canListenToRealmDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmDestroyed(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.close();
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }
}

Selenium v4.18

    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmCreated((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/blank', 'complete')
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {ScriptManager, BrowsingContext, Builder} = require("selenium-webdriver")
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue")
const {RealmType} = require("selenium-webdriver/bidi/realmInfo")
const {LocalValue, ChannelValue} = require("selenium-webdriver/bidi/protocolValue")
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");



describe('Script events', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to channel message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let message = null

    await manager.onMessage((m) => {
      message = m
    })

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createChannelValue(new ChannelValue('channel_name')))
    argumentValues.push(value)

    const result = await manager.callFunctionInBrowsingContext(
      await driver.getWindowHandle(),
      '(channel) => channel("foo")',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(message, null)
    assert.equal(message.channel, 'channel_name')
    assert.equal(message.data.type, 'string')
    assert.equal(message.data.value, 'foo')
  })

  it('can listen to realm created message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmCreated((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/blank', 'complete')

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })

  xit('can listen to realm destroyed message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmDestroyed((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.close()

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })
})

Realm Destroyed

Selenium v4.16

        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmDestroyed(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.close();
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.openqa.selenium.bidi.module.Script;
import org.openqa.selenium.bidi.browsingcontext.BrowsingContext;
import org.openqa.selenium.bidi.script.LocalValue;
import org.openqa.selenium.bidi.script.Message;
import org.openqa.selenium.bidi.script.RealmInfo;
import org.openqa.selenium.bidi.script.RealmType;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;

class ScriptEventsTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }
    
    @Test
    void canListenToChannelMessage()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<Message> future = new CompletableFuture<>();
            script.onMessage(future::complete);

            script.callFunctionInBrowsingContext(
                    driver.getWindowHandle(),
                    "(channel) => channel('foo')",
                    false,
                    Optional.of(List.of(LocalValue.channelValue("channel_name"))),
                    Optional.empty(),
                    Optional.empty());

            Message message = future.get(5, TimeUnit.SECONDS);
            Assertions.assertEquals("channel_name", message.getChannel());
        }
    }

    @Test
    @DisabledOnOs(value = OS.MAC, disabledReason = "Works locally, times out on CI")
    void canListenToRealmCreatedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmCreated(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.navigate("https://www.selenium.dev/selenium/blankPage");
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }

    @Test
    @Disabled
    void canListenToRealmDestroyedEvent()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (Script script = new Script(driver)) {
            CompletableFuture<RealmInfo> future = new CompletableFuture<>();
            script.onRealmDestroyed(future::complete);

            BrowsingContext context = new BrowsingContext(driver, driver.getWindowHandle());

            context.close();
            RealmInfo realmInfo = future.get(5, TimeUnit.SECONDS);
            Assertions.assertNotNull(realmInfo.getRealmId());
            Assertions.assertEquals(RealmType.WINDOW, realmInfo.getRealmType());
        }
    }
}

Selenium v4.19

    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmDestroyed((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.close()
Show full example
const assert = require("assert")
const firefox = require('selenium-webdriver/firefox')
const {ScriptManager, BrowsingContext, Builder} = require("selenium-webdriver")
const {ArgumentValue} = require("selenium-webdriver/bidi/argumentValue")
const {RealmType} = require("selenium-webdriver/bidi/realmInfo")
const {LocalValue, ChannelValue} = require("selenium-webdriver/bidi/protocolValue")
const {EvaluateResultType} = require("selenium-webdriver/bidi/evaluateResult");



describe('Script events', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('can listen to channel message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let message = null

    await manager.onMessage((m) => {
      message = m
    })

    let argumentValues = []
    let value = new ArgumentValue(LocalValue.createChannelValue(new ChannelValue('channel_name')))
    argumentValues.push(value)

    const result = await manager.callFunctionInBrowsingContext(
      await driver.getWindowHandle(),
      '(channel) => channel("foo")',
      false,
      argumentValues,
    )
    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.notEqual(message, null)
    assert.equal(message.channel, 'channel_name')
    assert.equal(message.data.type, 'string')
    assert.equal(message.data.value, 'foo')
  })

  it('can listen to realm created message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmCreated((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.navigate('https://www.selenium.dev/selenium/web/blank', 'complete')

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })

  xit('can listen to realm destroyed message', async function () {
    const manager = await ScriptManager(undefined, driver)

    let realmInfo = null

    await manager.onRealmDestroyed((result) => {
      realmInfo = result
    })

    const id = await driver.getWindowHandle()
    const browsingContext = await BrowsingContext(driver, {
      browsingContextId: id,
    })

    await browsingContext.close()

    assert.notEqual(realmInfo, null)
    assert.notEqual(realmInfo.realmId, null)
    assert.equal(realmInfo.realmType, RealmType.WINDOW)
  })
})

5.5 - BiDirectional API (W3C compliant)

Page being translated from English to Japanese. Do you speak Japanese? Help us to translate it by sending us pull requests!

This section contains the APIs related to logging.

Console logs

Listen to the console.log events and register callbacks to process the event.

Selenium v4.8

            CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
            logInspector.onConsoleEntry(future::complete);

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

            ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.time.Duration;
import java.util.concurrent.*;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import org.openqa.selenium.bidi.log.LogLevel;
import org.openqa.selenium.bidi.log.StackTrace;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

class LogTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
            logInspector.onConsoleEntry(future::complete);

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

            ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Hello, world!", logEntry.getText());

            Assertions.assertEquals(1, logEntry.getArgs().size());
            Assertions.assertEquals("console", logEntry.getType());
            Assertions.assertEquals("log", logEntry.getMethod());
            Assertions.assertNull(logEntry.getStackTrace());
        }
    }

    @Test
    void testListenToJavascriptLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptLog(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
            Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
        }
    }

    @Test
    void testListenToJavascriptErrorLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }

    @Test
    void testRetrieveStacktraceForALog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            StackTrace stackTrace = logEntry.getStackTrace();
            Assertions.assertNotNull(stackTrace);
            Assertions.assertEquals(4, stackTrace.getCallFrames().size());
        }
    }

    @Test
    void testListenToLogsWithMultipleConsumers()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> completableFuture1 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture1::complete);

            CompletableFuture<JavascriptLogEntry> completableFuture2 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture2::complete);

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

            JavascriptLogEntry logEntry = completableFuture1.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());

            logEntry = completableFuture2.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }
}
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'consoleLog'}).click()

    assert.equal(logEntry.text, 'Hello, world!')
    assert.equal(logEntry.realm, null)
    assert.equal(logEntry.type, 'console')
    assert.equal(logEntry.level, 'info')
    assert.equal(logEntry.method, 'log')
    assert.equal(logEntry.stackTrace, null)
    assert.equal(logEntry.args.length, 1)
Show full example
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const LogInspector = require('selenium-webdriver/bidi/logInspector');
const {Builder} = require("selenium-webdriver");


describe('Log Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test listen to console log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'consoleLog'}).click()

    assert.equal(logEntry.text, 'Hello, world!')
    assert.equal(logEntry.realm, null)
    assert.equal(logEntry.type, 'console')
    assert.equal(logEntry.level, 'info')
    assert.equal(logEntry.method, 'log')
    assert.equal(logEntry.stackTrace, null)
    assert.equal(logEntry.args.length, 1)

    await inspector.close()
  })

  it('test listen to javascript error log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    assert.equal(logEntry.text, 'Error: Not working')
    assert.equal(logEntry.type, 'javascript')
    assert.equal(logEntry.level, 'error')

    await inspector.close()
  })

  it('test retrieve stack trace for a log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    const stackTrace = logEntry.stackTrace
    assert.notEqual(stackTrace, null)
    assert.equal(stackTrace.callFrames.length, 3)

    await inspector.close()
  })

  it('test listen to logs with multiple consumers', async function () {
    let logEntry1 = null
    let logEntry2 = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry1 = log
    })
    await inspector.onJavascriptException(function (log) {
      logEntry2 = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    assert.equal(logEntry1.text, 'Error: Not working')
    assert.equal(logEntry1.type, 'javascript')
    assert.equal(logEntry1.level, 'error')

    assert.equal(logEntry2.text, 'Error: Not working')
    assert.equal(logEntry2.type, 'javascript')
    assert.equal(logEntry2.level, 'error')

    await inspector.close()
  })
})

JavaScript exceptions

Listen to the JS Exceptions and register callbacks to process the exception details.

            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.time.Duration;
import java.util.concurrent.*;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import org.openqa.selenium.bidi.log.LogLevel;
import org.openqa.selenium.bidi.log.StackTrace;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

class LogTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
            logInspector.onConsoleEntry(future::complete);

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

            ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Hello, world!", logEntry.getText());

            Assertions.assertEquals(1, logEntry.getArgs().size());
            Assertions.assertEquals("console", logEntry.getType());
            Assertions.assertEquals("log", logEntry.getMethod());
            Assertions.assertNull(logEntry.getStackTrace());
        }
    }

    @Test
    void testListenToJavascriptLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptLog(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
            Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
        }
    }

    @Test
    void testListenToJavascriptErrorLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }

    @Test
    void testRetrieveStacktraceForALog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            StackTrace stackTrace = logEntry.getStackTrace();
            Assertions.assertNotNull(stackTrace);
            Assertions.assertEquals(4, stackTrace.getCallFrames().size());
        }
    }

    @Test
    void testListenToLogsWithMultipleConsumers()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> completableFuture1 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture1::complete);

            CompletableFuture<JavascriptLogEntry> completableFuture2 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture2::complete);

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

            JavascriptLogEntry logEntry = completableFuture1.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());

            logEntry = completableFuture2.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }
}
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    assert.equal(logEntry.text, 'Error: Not working')
    assert.equal(logEntry.type, 'javascript')
    assert.equal(logEntry.level, 'error')
Show full example
const assert = require("assert");
const firefox = require('selenium-webdriver/firefox');
const LogInspector = require('selenium-webdriver/bidi/logInspector');
const {Builder} = require("selenium-webdriver");


describe('Log Inspector', function () {
  let driver

  beforeEach(async function () {
    driver = new Builder()
      .forBrowser('firefox')
      .setFirefoxOptions(new firefox.Options().enableBidi())
      .build()
  })

  afterEach(async function () {
    await driver.quit()
  })

  it('test listen to console log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onConsoleEntry(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'consoleLog'}).click()

    assert.equal(logEntry.text, 'Hello, world!')
    assert.equal(logEntry.realm, null)
    assert.equal(logEntry.type, 'console')
    assert.equal(logEntry.level, 'info')
    assert.equal(logEntry.method, 'log')
    assert.equal(logEntry.stackTrace, null)
    assert.equal(logEntry.args.length, 1)

    await inspector.close()
  })

  it('test listen to javascript error log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    assert.equal(logEntry.text, 'Error: Not working')
    assert.equal(logEntry.type, 'javascript')
    assert.equal(logEntry.level, 'error')

    await inspector.close()
  })

  it('test retrieve stack trace for a log', async function () {
    let logEntry = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    const stackTrace = logEntry.stackTrace
    assert.notEqual(stackTrace, null)
    assert.equal(stackTrace.callFrames.length, 3)

    await inspector.close()
  })

  it('test listen to logs with multiple consumers', async function () {
    let logEntry1 = null
    let logEntry2 = null
    const inspector = await LogInspector(driver)
    await inspector.onJavascriptException(function (log) {
      logEntry1 = log
    })
    await inspector.onJavascriptException(function (log) {
      logEntry2 = log
    })

    await driver.get('https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html')
    await driver.findElement({id: 'jsException'}).click()

    assert.equal(logEntry1.text, 'Error: Not working')
    assert.equal(logEntry1.type, 'javascript')
    assert.equal(logEntry1.level, 'error')

    assert.equal(logEntry2.text, 'Error: Not working')
    assert.equal(logEntry2.type, 'javascript')
    assert.equal(logEntry2.level, 'error')

    await inspector.close()
  })
})

Listen to JS Logs

Listen to all JS logs at all levels and register callbacks to process the log.

Selenium v4.8

            logInspector.onJavaScriptLog(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);
Show full example
package dev.selenium.bidirectional.webdriver_bidi;

import dev.selenium.BaseTest;

import java.time.Duration;
import java.util.concurrent.*;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.bidi.module.LogInspector;
import org.openqa.selenium.bidi.log.ConsoleLogEntry;
import org.openqa.selenium.bidi.log.JavascriptLogEntry;
import org.openqa.selenium.bidi.log.LogLevel;
import org.openqa.selenium.bidi.log.StackTrace;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.support.ui.WebDriverWait;

class LogTest extends BaseTest {

    @BeforeEach
    public void setup() {
        FirefoxOptions options = new FirefoxOptions();
        options.setCapability("webSocketUrl", true);
        driver = new FirefoxDriver(options);
    }

    @Test
    void testListenToConsoleLog() throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<ConsoleLogEntry> future = new CompletableFuture<>();
            logInspector.onConsoleEntry(future::complete);

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

            ConsoleLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Hello, world!", logEntry.getText());

            Assertions.assertEquals(1, logEntry.getArgs().size());
            Assertions.assertEquals("console", logEntry.getType());
            Assertions.assertEquals("log", logEntry.getMethod());
            Assertions.assertNull(logEntry.getStackTrace());
        }
    }

    @Test
    void testListenToJavascriptLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptLog(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
            Assertions.assertEquals(LogLevel.ERROR, logEntry.getLevel());
        }
    }

    @Test
    void testListenToJavascriptErrorLog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }

    @Test
    void testRetrieveStacktraceForALog()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> future = new CompletableFuture<>();
            logInspector.onJavaScriptException(future::complete);

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

            JavascriptLogEntry logEntry = future.get(5, TimeUnit.SECONDS);

            StackTrace stackTrace = logEntry.getStackTrace();
            Assertions.assertNotNull(stackTrace);
            Assertions.assertEquals(4, stackTrace.getCallFrames().size());
        }
    }

    @Test
    void testListenToLogsWithMultipleConsumers()
            throws ExecutionException, InterruptedException, TimeoutException {
        try (LogInspector logInspector = new LogInspector(driver)) {
            CompletableFuture<JavascriptLogEntry> completableFuture1 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture1::complete);

            CompletableFuture<JavascriptLogEntry> completableFuture2 = new CompletableFuture<>();
            logInspector.onJavaScriptLog(completableFuture2::complete);

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

            JavascriptLogEntry logEntry = completableFuture1.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());

            logEntry = completableFuture2.get(5, TimeUnit.SECONDS);

            Assertions.assertEquals("Error: Not working", logEntry.getText());
            Assertions.assertEquals("javascript", logEntry.getType());
        }
    }
}