Script
Commands
This section contains the APIs related to script commands.
Call function in a browsing context
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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));
}
}
}
}
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
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());
}
}
}
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
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());
}
}
}
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
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());
}
}
}
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)
})
})