Script

Commands

This section contains the APIs related to script commands.

Call function in a browsing context

Selenium v4.15

    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());
        }

Selenium v4.15

  it 'calls a function' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'

    result = driver.script.call_function(
      'function(a, b) { return a + b; }',
      args: [
        {type: 'number', value: 2},
        {type: 'number', value: 3}
      ]
    )

    expect(result['type']).to eq('number')
    expect(result['value']).to eq(5)
  end

Selenium v4.9

  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)
  })

Selenium v4.15

@pytest.mark.driver_type("bidi")
def test_call_function(driver):
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    result = driver.script.call_function(
        "function(a, b) { return a + b; }",
        args=[{"type": "number", "value": 2}, {"type": "number", "value": 3}]
    )

    assert result.get("type") == "number"
    assert result.get("value") == 5


@pytest.mark.driver_type("bidi")
def test_evaluate_script(driver):

Call function in a sandbox

Selenium v4.15

    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());
        }

Selenium v4.9

    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',
    )

Call function in a realm

Selenium v4.15

    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());
        }

Selenium v4.15


    realms = driver.script.get_realms
    realm_id = realms.first['realm']

    result = driver.script.evaluate('1 + 1', realm: realm_id)

    expect(result['type']).to eq('number')
    expect(result['value']).to eq(2)
  end

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)

    const result = await manager.callFunctionInRealm(realmId, '() => window.foo', true)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

Selenium v4.15

    mutation_events = []

    def on_mutation(event):
        mutation_events.append(event)

    driver.script.add_dom_mutation_handler(on_mutation)
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    script = """
    const div = document.createElement('div');
    div.textContent = 'Hello';
    document.body.appendChild(div);
    """
    driver.execute_script(script)

    wait = WebDriverWait(driver, 5)
    wait.until(lambda _: len(mutation_events) > 0)

Evaluate script in a browsing context

Selenium v4.15

    @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());

Selenium v4.15

  it 'evaluates a script' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'

    result = driver.script.evaluate('2 + 2')

    expect(result['type']).to eq('number')
    expect(result['value']).to eq(4)
  end

Selenium v4.9

    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)
  })

Selenium v4.15

    result = driver.script.evaluate("2 + 2")

    assert result.get("type") == "number"
    assert result.get("value") == 4


@pytest.mark.driver_type("bidi")
def test_disown_value(driver):
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

Evaluate script in a sandbox

Selenium v4.15


            EvaluateResultSuccess successResult = (EvaluateResultSuccess) result;
            Assertions.assertTrue(successResult.getResult().getHandle().isPresent());
        }
    }

    @Test
    void canEvaluateInASandBox() {
        String id = driver.getWindowHandle();
        try (Script script = new Script(id, driver)) {

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')

    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()

Evaluate script in a realm

Selenium v4.15

                            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();

Selenium v4.15

    mutation_events = []

    driver.script.add_dom_mutation_handler do |event|
      mutation_events << event
    end

    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'

    driver.execute_script(<<~SCRIPT)
      const div = document.createElement('div');

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)

    assert.equal(result.resultType, EvaluateResultType.SUCCESS)
    assert.equal(result.result.value, 3)
  })

Selenium v4.15

    mutation_events = []

    def on_mutation(event):
        mutation_events.append(event)

    driver.script.add_dom_mutation_handler(on_mutation)
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    script = """
    const div = document.createElement('div');
    div.textContent = 'Hello';
    document.body.appendChild(div);
    """
    driver.execute_script(script)

    wait = WebDriverWait(driver, 5)
    wait.until(lambda _: len(mutation_events) > 0)

Disown handles in a browsing context

Selenium v4.15

            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(

Selenium v4.15

  it 'disowns a value' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'

    result = driver.script.evaluate('({x: 1})')
    handle = result['handle']

    expect { driver.script.disown(handles: [handle]) }.not_to raise_error
  end

Selenium v4.9

    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})

Selenium v4.15

    handle = result.get("handle")

    # Disown the value
    driver.script.disown(handles=[handle])
    # If no exception is raised, disown was successful


@pytest.mark.driver_type("bidi")
def test_call_function_with_element_args(driver):
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    element = driver.find_element(By.ID, "consoleLog")

    result = driver.script.call_function(

Disown handles in a realm

Selenium v4.15

    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()));
        }
    }

Selenium v4.9

    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)
  })

Get all realms

Selenium v4.15

    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());
        }
    }

Selenium v4.15


    realms = driver.script.get_realms
    realm_id = realms.first['realm']

    result = driver.script.evaluate('1 + 1', realm: realm_id)

    expect(result['type']).to eq('number')
    expect(result['value']).to eq(2)
  end

Selenium v4.9

    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)
  })

Selenium v4.15

    mutation_events = []

    def on_mutation(event):
        mutation_events.append(event)

    driver.script.add_dom_mutation_handler(on_mutation)
    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    script = """
    const div = document.createElement('div');
    div.textContent = 'Hello';
    document.body.appendChild(div);
    """
    driver.execute_script(script)

    wait = WebDriverWait(driver, 5)
    wait.until(lambda _: len(mutation_events) > 0)

Get realm by type

Selenium v4.15

    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());
        }
    }

Selenium v4.9

    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]

Get browsing context realms

Selenium v4.15

    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());
        }
    }

Selenium v4.9

  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)

Get browsing context realms by type

Selenium v4.15

    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());
        }

Selenium v4.9

    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) {

Preload a script

Selenium v4.15


    @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());
            }

Selenium v4.10


  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',
    )

Remove a preloaded script

Selenium v4.15

            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<>();

Selenium v4.10

  })
})

Events

This section contains the APIs related to script events.

Message

Selenium v4.16

    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

Selenium v4.16

  it 'calls function with element arguments' do
    driver.navigate.to 'https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html'

    element = driver.find_element(id: 'consoleLog')

    result = driver.script.call_function(
      'function(elem) { return elem.tagName; }',
      args: [
        {type: 'HTMLElement', handle: element}
      ]
    )

    expect(result['value']).to eq('BUTTON')

Selenium v4.18


  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')

Selenium v4.16

    driver.get("https://www.selenium.dev/selenium/web/bidi/logEntryAdded.html")

    element = driver.find_element(By.ID, "consoleLog")

    result = driver.script.call_function(
        "function(elem) { return elem.tagName; }",
        args=[{"type": "HTMLElement", "handle": element}]
    )

    assert result.get("value") == "BUTTON"

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());
        }
    }

    @Test
    @Disabled

Selenium v4.18


  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')

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());
        }
    }
}

Selenium v4.19


  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()

DOM Mutation

Selenium v4.16

    SCRIPT

    wait.until { mutation_events.any? }

    expect(mutation_events).not_to be_empty
  end
end

Selenium v4.16

  it('can listen to dom mutations', async function () {
    let message = null
    await driver.script().addDomMutationHandler((m) => {
      message = m
    })

    await driver.get('https://www.selenium.dev/selenium/web/dynamic')

    let element = driver.findElement({ id: 'reveal' })
    await element.click()
    let revealed = driver.findElement({ id: 'revealed' })
    await driver.wait(until.elementIsVisible(revealed), 5000)

    assert.strictEqual(message['attribute_name'], 'style')
    assert.strictEqual(message['current_value'], '')
    assert.strictEqual(message['old_value'], 'display:none;')
  })

Selenium v4.16

Last modified May 22, 2026: fix tests and docs using them (11d973dea8)