diff --git a/java/src/org/openqa/selenium/bidi/script/RemoteValue.java b/java/src/org/openqa/selenium/bidi/script/RemoteValue.java index 677cba41cb19d2..ec3e847a3e69cc 100644 --- a/java/src/org/openqa/selenium/bidi/script/RemoteValue.java +++ b/java/src/org/openqa/selenium/bidi/script/RemoteValue.java @@ -193,38 +193,57 @@ private Map toJson() { } private static Object deserializeValue(Object value, Type type) { - - if (Type.ARRAY.equals(type) || Type.SET.equals(type)) { - try (StringReader reader = new StringReader(JSON.toJson(value)); - JsonInput input = JSON.newInput(reader)) { - value = input.read(new TypeToken>() {}.getType()); - } - } else if (Type.MAP.equals(type) || Type.OBJECT.equals(type)) { - List> result = (List>) value; - Map map = new HashMap<>(); - - for (List list : result) { - Object key = list.get(0); - if (!(key instanceof String)) { - try (StringReader reader = new StringReader(JSON.toJson(key)); - JsonInput keyInput = JSON.newInput(reader)) { - key = keyInput.read(RemoteValue.class); + Object finalValue; + + switch (type) { + case ARRAY: + case SET: + try (StringReader reader = new StringReader(JSON.toJson(value)); + JsonInput input = JSON.newInput(reader)) { + finalValue = input.read(new TypeToken>() {}.getType()); + } + break; + + case MAP: + case OBJECT: + List> result = (List>) value; + Map map = new HashMap<>(); + + for (List list : result) { + Object key = list.get(0); + if (!(key instanceof String)) { + try (StringReader reader = new StringReader(JSON.toJson(key)); + JsonInput keyInput = JSON.newInput(reader)) { + key = keyInput.read(RemoteValue.class); + } + } + try (StringReader reader = new StringReader(JSON.toJson(list.get(1))); + JsonInput valueInput = JSON.newInput(reader)) { + RemoteValue value1 = valueInput.read(RemoteValue.class); + map.put(key, value1); } } - try (StringReader reader = new StringReader(JSON.toJson(list.get(1))); - JsonInput valueInput = JSON.newInput(reader)) { - RemoteValue value1 = valueInput.read(RemoteValue.class); - map.put(key, value1); + finalValue = map; + break; + + case REGULAR_EXPRESSION: + try (StringReader reader = new StringReader(JSON.toJson(value)); + JsonInput input = JSON.newInput(reader)) { + finalValue = input.read(RegExpValue.class); } - } - value = map; - } else if (Type.REGULAR_EXPRESSION.equals(type)) { - try (StringReader reader = new StringReader(JSON.toJson(value)); - JsonInput input = JSON.newInput(reader)) { - value = input.read(RegExpValue.class); - } + break; + + case WINDOW: + try (StringReader reader = new StringReader(JSON.toJson(value)); + JsonInput input = JSON.newInput(reader)) { + finalValue = input.read(WindowProxyProperties.class); + } + break; + + default: + finalValue = value; } - return value; + return finalValue; } } diff --git a/java/src/org/openqa/selenium/bidi/script/WindowProxyProperties.java b/java/src/org/openqa/selenium/bidi/script/WindowProxyProperties.java new file mode 100644 index 00000000000000..d86a1b5f6c1b9c --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/script/WindowProxyProperties.java @@ -0,0 +1,53 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.openqa.selenium.bidi.script; + +import org.openqa.selenium.json.JsonInput; + +public class WindowProxyProperties { + + private final String browsingContext; + + private WindowProxyProperties(String browsingContext) { + this.browsingContext = browsingContext; + } + + public static WindowProxyProperties fromJson(JsonInput input) { + String browsingContext = null; + + input.beginObject(); + while (input.hasNext()) { + switch (input.nextName()) { + case "context": + browsingContext = input.read(String.class); + break; + + default: + input.skipValue(); + break; + } + } + + input.endObject(); + + return new WindowProxyProperties(browsingContext); + } + + public String getBrowsingContext() { + return browsingContext; + } +} diff --git a/java/src/org/openqa/selenium/grid/commands/Standalone.java b/java/src/org/openqa/selenium/grid/commands/Standalone.java index ec3c0080d5262e..fd8315ff95d7de 100644 --- a/java/src/org/openqa/selenium/grid/commands/Standalone.java +++ b/java/src/org/openqa/selenium/grid/commands/Standalone.java @@ -222,7 +222,7 @@ protected Handlers createHandlers(Config config) { httpHandler = combine(httpHandler, Route.get("/readyz").to(() -> readinessCheck)); Node node = createNode(config, bus, distributor, combinedHandler); - return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node)); + return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node, subPath)); } @Override diff --git a/java/src/org/openqa/selenium/grid/distributor/config/BUILD.bazel b/java/src/org/openqa/selenium/grid/distributor/config/BUILD.bazel index 4207ae8dff8f4c..f75ae55ab77201 100644 --- a/java/src/org/openqa/selenium/grid/distributor/config/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/distributor/config/BUILD.bazel @@ -13,6 +13,7 @@ java_library( "//java/src/org/openqa/selenium/grid/data", "//java/src/org/openqa/selenium/grid/distributor", "//java/src/org/openqa/selenium/grid/distributor/selector", + "//java/src/org/openqa/selenium/grid/server", artifact("com.beust:jcommander"), ], ) diff --git a/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java b/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java index ddff2ddcd76939..1bc11a5bed5750 100644 --- a/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java +++ b/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java @@ -56,18 +56,20 @@ public class ProxyNodeWebsockets ImmutableSet.of("goog:chromeOptions", "moz:debuggerAddress", "ms:edgeOptions"); private final HttpClient.Factory clientFactory; private final Node node; + private final String gridSubPath; - public ProxyNodeWebsockets(HttpClient.Factory clientFactory, Node node) { + public ProxyNodeWebsockets(HttpClient.Factory clientFactory, Node node, String gridSubPath) { this.clientFactory = Objects.requireNonNull(clientFactory); this.node = Objects.requireNonNull(node); + this.gridSubPath = gridSubPath; } @Override public Optional> apply(String uri, Consumer downstream) { - UrlTemplate.Match fwdMatch = FWD_TEMPLATE.match(uri); - UrlTemplate.Match cdpMatch = CDP_TEMPLATE.match(uri); - UrlTemplate.Match bidiMatch = BIDI_TEMPLATE.match(uri); - UrlTemplate.Match vncMatch = VNC_TEMPLATE.match(uri); + UrlTemplate.Match fwdMatch = FWD_TEMPLATE.match(uri, gridSubPath); + UrlTemplate.Match cdpMatch = CDP_TEMPLATE.match(uri, gridSubPath); + UrlTemplate.Match bidiMatch = BIDI_TEMPLATE.match(uri, gridSubPath); + UrlTemplate.Match vncMatch = VNC_TEMPLATE.match(uri, gridSubPath); if (bidiMatch == null && cdpMatch == null && vncMatch == null && fwdMatch == null) { return Optional.empty(); diff --git a/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java b/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java index bbec41c58ed246..cdaaf1038479ee 100644 --- a/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java +++ b/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java @@ -162,6 +162,21 @@ public boolean isManagedDownloadsEnabled() { return config.getBool(NODE_SECTION, "enable-managed-downloads").orElse(Boolean.FALSE); } + public String getGridSubPath() { + return normalizeSubPath(getPublicGridUri().map(URI::getPath).orElse("")); + } + + public static String normalizeSubPath(String prefix) { + prefix = prefix.trim(); + if (!prefix.startsWith("/")) { + prefix = "/" + prefix; // Prefix with a '/' if absent. + } + if (prefix.endsWith("/")) { + prefix = prefix.substring(0, prefix.length() - 1); // Remove the trailing '/' if present. + } + return prefix; + } + public Node getNode() { return config.getClass(NODE_SECTION, "implementation", Node.class, DEFAULT_NODE_IMPLEMENTATION); } diff --git a/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java b/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java index 59ea96ea8c3c0c..c86429aeaff645 100644 --- a/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java +++ b/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java @@ -171,7 +171,8 @@ protected Handlers createHandlers(Config config) { Route httpHandler = Route.combine(node, get("/readyz").to(() -> readinessCheck)); - return new Handlers(httpHandler, new ProxyNodeWebsockets(clientFactory, node)); + return new Handlers( + httpHandler, new ProxyNodeWebsockets(clientFactory, node, nodeOptions.getGridSubPath())); } @Override diff --git a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java index 1c7b2f31b156c5..0e5d2831585366 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java @@ -838,9 +838,7 @@ private Session createExternalSession( private URI rewrite(String path) { try { String scheme = "https".equals(gridUri.getScheme()) ? "wss" : "ws"; - if (gridUri.getPath() != null && !gridUri.getPath().equals("/")) { - path = gridUri.getPath() + path; - } + path = NodeOptions.normalizeSubPath(gridUri.getPath()) + path; return new URI( scheme, gridUri.getUserInfo(), gridUri.getHost(), gridUri.getPort(), path, null, null); } catch (URISyntaxException e) { diff --git a/java/src/org/openqa/selenium/grid/security/SecretOptions.java b/java/src/org/openqa/selenium/grid/security/SecretOptions.java index 7c12e27b90d6b6..35c57458f353d1 100644 --- a/java/src/org/openqa/selenium/grid/security/SecretOptions.java +++ b/java/src/org/openqa/selenium/grid/security/SecretOptions.java @@ -27,7 +27,6 @@ import org.openqa.selenium.UsernameAndPassword; import org.openqa.selenium.grid.config.Config; import org.openqa.selenium.grid.config.ConfigException; -import org.openqa.selenium.grid.server.BaseServerOptions; public class SecretOptions { @@ -42,8 +41,7 @@ public SecretOptions(Config config) { public Secret getRegistrationSecret() { String secret = ""; - BaseServerOptions serverOptions = new BaseServerOptions(config); - if ((serverOptions.isSecure() || serverOptions.isSelfSigned()) + if ((isSecure() || isSelfSigned()) && !config.get(SERVER_SECTION, "registration-secret").isPresent()) { try { secret = @@ -72,6 +70,15 @@ public UsernameAndPassword getServerAuthentication() { return new UsernameAndPassword(username.get(), password.get()); } + private boolean isSecure() { + return config.get(SERVER_SECTION, "https-private-key").isPresent() + && config.get(SERVER_SECTION, "https-certificate").isPresent(); + } + + private boolean isSelfSigned() { + return config.getBool(SERVER_SECTION, "https-self-signed").orElse(false); + } + private File getCertificate() { String certificatePath = config.get(SERVER_SECTION, "https-certificate").orElse(null); if (certificatePath != null) { diff --git a/java/src/org/openqa/selenium/grid/sessionmap/config/BUILD.bazel b/java/src/org/openqa/selenium/grid/sessionmap/config/BUILD.bazel index 9ed88ffc805ad6..e0524896ec6f15 100644 --- a/java/src/org/openqa/selenium/grid/sessionmap/config/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/sessionmap/config/BUILD.bazel @@ -11,6 +11,7 @@ java_library( "//java:auto-service", "//java/src/org/openqa/selenium/grid/config", "//java/src/org/openqa/selenium/grid/sessionmap", + "//java/src/org/openqa/selenium/grid/server", artifact("com.beust:jcommander"), ], ) diff --git a/java/src/org/openqa/selenium/grid/sessionqueue/config/BUILD.bazel b/java/src/org/openqa/selenium/grid/sessionqueue/config/BUILD.bazel index db10f5fb227fc5..524b595100741a 100644 --- a/java/src/org/openqa/selenium/grid/sessionqueue/config/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/sessionqueue/config/BUILD.bazel @@ -13,6 +13,7 @@ java_library( "//java/src/org/openqa/selenium/grid/config", "//java/src/org/openqa/selenium/grid/jmx", "//java/src/org/openqa/selenium/grid/sessionqueue", + "//java/src/org/openqa/selenium/grid/server", artifact("com.beust:jcommander"), ], ) diff --git a/java/src/org/openqa/selenium/remote/http/UrlTemplate.java b/java/src/org/openqa/selenium/remote/http/UrlTemplate.java index 0e8e2d5737b46b..c0d6d583cf7c5c 100644 --- a/java/src/org/openqa/selenium/remote/http/UrlTemplate.java +++ b/java/src/org/openqa/selenium/remote/http/UrlTemplate.java @@ -139,6 +139,20 @@ public UrlTemplate.Match match(String matchAgainst) { return compiled.apply(matchAgainst); } + /** + * @return A {@link Match} with all parameters filled if successful, null otherwise. Remove + * subPath from matchAgainst before matching. + */ + public UrlTemplate.Match match(String matchAgainst, String prefix) { + if (matchAgainst == null || prefix == null) { + return null; + } + if (!prefix.isEmpty() && !prefix.equals("/")) { + matchAgainst = matchAgainst.replaceFirst(prefix, ""); + } + return match(matchAgainst); + } + @SuppressWarnings("InnerClassMayBeStatic") public class Match { private final String url; diff --git a/java/test/org/openqa/selenium/bidi/script/ScriptCommandsTest.java b/java/test/org/openqa/selenium/bidi/script/ScriptCommandsTest.java index f834e99267912c..fd66f237fc754a 100644 --- a/java/test/org/openqa/selenium/bidi/script/ScriptCommandsTest.java +++ b/java/test/org/openqa/selenium/bidi/script/ScriptCommandsTest.java @@ -38,6 +38,7 @@ import org.junit.jupiter.api.AfterEach; 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.LogInspector; @@ -114,6 +115,43 @@ void canCallFunctionWithArguments() { assertThat(((List) successResult.getResult().getValue().get()).size()).isEqualTo(2); } + @Test + @NotYetImplemented(SAFARI) + @NotYetImplemented(IE) + @NotYetImplemented(EDGE) + @NotYetImplemented(CHROME) + void canCallFunctionToGetIFrameBrowsingContext() { + String url = appServer.whereIs("click_too_big_in_frame.html"); + driver.get(url); + + driver.findElement(By.id("iframe1")); + + String id = driver.getWindowHandle(); + Script script = new Script(id, driver); + + List arguments = new ArrayList<>(); + + EvaluateResult result = + script.callFunctionInBrowsingContext( + id, + "() => document.querySelector('iframe[id=\"iframe1\"]').contentWindow", + false, + Optional.of(arguments), + Optional.empty(), + Optional.empty()); + + assertThat(result.getResultType()).isEqualTo(EvaluateResult.Type.SUCCESS); + assertThat(result.getRealmId()).isNotNull(); + + EvaluateResultSuccess successResult = (EvaluateResultSuccess) result; + assertThat(successResult.getResult().getType()).isEqualTo("window"); + assertThat(successResult.getResult().getValue().isPresent()).isTrue(); + assertThat( + ((WindowProxyProperties) successResult.getResult().getValue().get()) + .getBrowsingContext()) + .isNotNull(); + } + @Test @NotYetImplemented(SAFARI) @NotYetImplemented(IE) diff --git a/java/test/org/openqa/selenium/grid/node/config/NodeOptionsTest.java b/java/test/org/openqa/selenium/grid/node/config/NodeOptionsTest.java index e0050ab161bfc0..43d413cdab3628 100644 --- a/java/test/org/openqa/selenium/grid/node/config/NodeOptionsTest.java +++ b/java/test/org/openqa/selenium/grid/node/config/NodeOptionsTest.java @@ -673,6 +673,28 @@ void settingTheHubWithDefaultValueSetsTheGridUrlToTheNonLoopbackAddress() { .isEqualTo(Optional.of(URI.create(nonLoopbackAddressUrl))); } + @Test + void settingSubPathForNodeServerExtractFromGridUrl() { + String[] rawConfig = + new String[] { + "[node]", "grid-url = \"http://localhost:4444/mySubPath\"", + }; + Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig))); + NodeOptions nodeOptions = new NodeOptions(config); + assertThat(nodeOptions.getGridSubPath()).isEqualTo("/mySubPath"); + } + + @Test + void settingSubPathForNodeServerExtractFromHub() { + String[] rawConfig = + new String[] { + "[node]", "hub = \"http://0.0.0.0:4444/mySubPath\"", + }; + Config config = new TomlConfig(new StringReader(String.join("\n", rawConfig))); + NodeOptions nodeOptions = new NodeOptions(config); + assertThat(nodeOptions.getGridSubPath()).isEqualTo("/mySubPath"); + } + @Test void notSettingSlotMatcherAvailable() { String[] rawConfig = diff --git a/java/test/org/openqa/selenium/remote/http/UrlTemplateTest.java b/java/test/org/openqa/selenium/remote/http/UrlTemplateTest.java index c8703235885aa7..862c22e0c7bf8f 100644 --- a/java/test/org/openqa/selenium/remote/http/UrlTemplateTest.java +++ b/java/test/org/openqa/selenium/remote/http/UrlTemplateTest.java @@ -67,6 +67,24 @@ void itIsFineForTheFirstCharacterToBeAPattern() { assertThat(match.getParameters()).isEqualTo(ImmutableMap.of("cake", "cheese")); } + @Test + void shouldMatchAgainstUrlTemplateExcludePrefix() { + UrlTemplate.Match match = + new UrlTemplate("/session/{id}/se/vnc").match("/prefix/session/1234/se/vnc", "/prefix"); + + assertThat(match.getUrl()).isEqualTo("/session/1234/se/vnc"); + assertThat(match.getParameters()).isEqualTo(ImmutableMap.of("id", "1234")); + } + + @Test + void shouldMatchAgainstUrlTemplateWithEmptyPrefix() { + UrlTemplate.Match match = + new UrlTemplate("/session/{id}/se/vnc").match("/session/1234/se/vnc", ""); + + assertThat(match.getUrl()).isEqualTo("/session/1234/se/vnc"); + assertThat(match.getParameters()).isEqualTo(ImmutableMap.of("id", "1234")); + } + @Test void aNullMatchDoesNotCauseANullPointerExceptionToBeThrown() { assertThat(new UrlTemplate("/").match(null)).isNull(); diff --git a/javascript/node/selenium-webdriver/test/bidi/bidi_session_test.js b/javascript/node/selenium-webdriver/test/bidi/bidi_session_test.js new file mode 100644 index 00000000000000..5fb744463ec9cf --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/bidi_session_test.js @@ -0,0 +1,51 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser} = require('../../') +const {suite} = require('../../lib/test') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Session', function () { + it('can create bidi session', async function () { + const bidi = await driver.getBidi() + const status = await bidi.status + + assert('ready' in status['result']) + assert.notEqual(status['result']['message'], null) + }) + }) + }, + {browsers: [Browser.FIREFOX]} +) diff --git a/javascript/node/selenium-webdriver/test/bidi/bidi_test.js b/javascript/node/selenium-webdriver/test/bidi/bidi_test.js index 209f96ca5ae9e8..5cb7feed9d5645 100644 --- a/javascript/node/selenium-webdriver/test/bidi/bidi_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/bidi_test.js @@ -17,34 +17,14 @@ 'use strict' -// Imports for LogInspector and BrowsingContext const assert = require('assert') const firefox = require('../../firefox') const { Browser, By, WebElement } = require('../../') const { Pages, suite } = require('../../lib/test') const logInspector = require('../../bidi/logInspector') const BrowsingContext = require('../../bidi/browsingContext') -const BrowsingContextInspector = require('../../bidi/browsingContextInspector') -const NetworkInspector = require('../../bidi/networkInspector') -const filterBy = require('../../bidi/filterBy') const until = require('../../lib/until') -// Imports for Script Module -const ScriptManager = require('../../bidi/scriptManager') -const { - ChannelValue, - LocalValue, - ReferenceValue, - RemoteReferenceType, - RegExpValue, -} = require('../../bidi/protocolValue') -const { ArgumentValue } = require('../../bidi/argumentValue') -const { EvaluateResultType } = require('../../bidi/evaluateResult') -const { ResultOwnership } = require('../../bidi/resultOwnership') -const { SpecialNumberType } = require('../../bidi/protocolType') -const { RealmType } = require('../../bidi/realmInfo') -const { WebDriverError } = require('../../lib/error') - suite( function (env) { let driver @@ -60,2364 +40,6 @@ suite( await driver.quit() }) - describe('Session', function () { - it('can create bidi session', async function () { - const bidi = await driver.getBidi() - const status = await bidi.status - - assert('ready' in status['result']) - assert.notEqual(status['result']['message'], null) - }) - }) - - describe('Log Inspector', function () { - it('can listen to console log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onConsoleEntry(function (log) { - logEntry = log - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry.text, 'Hello, world!') - assert.equal(logEntry.realm, null) - assert.equal(logEntry.type, 'console') - assert.equal(logEntry.level, 'info') - assert.equal(logEntry.method, 'log') - assert.equal(logEntry.stackTrace, null) - assert.equal(logEntry.args.length, 1) - - await inspector.close() - }) - - it('can listen to console log with different consumers', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onConsoleEntry(function (log) { - logEntry = log - }) - - let logEntryText = null - await inspector.onConsoleEntry(function (log) { - logEntryText = log.text - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry.text, 'Hello, world!') - assert.equal(logEntry.realm, null) - assert.equal(logEntry.type, 'console') - assert.equal(logEntry.level, 'info') - assert.equal(logEntry.method, 'log') - assert.equal(logEntry.stackTrace, null) - assert.equal(logEntry.args.length, 1) - - assert.equal(logEntryText, 'Hello, world!') - - await inspector.close() - }) - - it('can filter console info level log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onConsoleEntry(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('info')) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry.text, 'Hello, world!') - assert.equal(logEntry.realm, null) - assert.equal(logEntry.type, 'console') - assert.equal(logEntry.level, 'info') - assert.equal(logEntry.method, 'log') - assert.equal(logEntry.stackTrace, null) - assert.equal(logEntry.args.length, 1) - - await inspector.close() - }) - - it('can filter console log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onConsoleEntry(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('error')) - - await driver.get(Pages.logEntryAdded) - // Generating info level log but we are filtering by error level - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry, null) - await inspector.close() - }) - - it('can listen to javascript log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onJavascriptLog(function (log) { - logEntry = log - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - assert.equal(logEntry.text, 'Error: Not working') - assert.equal(logEntry.type, 'javascript') - assert.equal(logEntry.level, 'error') - - await inspector.close() - }) - - it('can filter javascript log at error level', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onJavascriptLog(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('error')) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - assert.equal(logEntry.text, 'Error: Not working') - assert.equal(logEntry.type, 'javascript') - assert.equal(logEntry.level, 'error') - - await inspector.close() - }) - - it('can filter javascript log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onJavascriptLog(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('info')) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - assert.equal(logEntry, null) - - await inspector.close() - }) - - it('can listen to javascript error log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onJavascriptException(function (log) { - logEntry = log - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - assert.equal(logEntry.text, 'Error: Not working') - assert.equal(logEntry.type, 'javascript') - assert.equal(logEntry.level, 'error') - - await inspector.close() - }) - - it('can retrieve stack trace for a log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onJavascriptException(function (log) { - logEntry = log - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - const stackTrace = logEntry.stackTrace - assert.notEqual(stackTrace, null) - assert.equal(stackTrace.callFrames.length, 3) - - await inspector.close() - }) - - it('can listen to any log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onLog(function (log) { - logEntry = log - }) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry.text, 'Hello, world!') - assert.equal(logEntry.realm, null) - assert.equal(logEntry.type, 'console') - assert.equal(logEntry.level, 'info') - assert.equal(logEntry.method, 'log') - assert.equal(logEntry.stackTrace, null) - assert.equal(logEntry.args.length, 1) - - await inspector.close() - }) - - it('can filter any log', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onLog(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('info')) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'consoleLog' }).click() - - assert.equal(logEntry.text, 'Hello, world!') - assert.equal(logEntry.realm, null) - assert.equal(logEntry.type, 'console') - assert.equal(logEntry.level, 'info') - assert.equal(logEntry.method, 'log') - assert.equal(logEntry.stackTrace, null) - assert.equal(logEntry.args.length, 1) - - await inspector.close() - }) - - it('can filter any log at error level', async function () { - let logEntry = null - const inspector = await logInspector(driver) - await inspector.onLog(function (log) { - logEntry = log - }, filterBy.FilterBy.logLevel('error')) - - await driver.get(Pages.logEntryAdded) - await driver.findElement({ id: 'jsException' }).click() - - assert.equal(logEntry.text, 'Error: Not working') - assert.equal(logEntry.type, 'javascript') - assert.equal(logEntry.level, 'error') - await inspector.close() - }) - }) - - describe('Browsing Context', function () { - let startIndex = 0 - let endIndex = 5 - let pdfMagicNumber = 'JVBER' - let pngMagicNumber = 'iVBOR' - - it('can create a browsing context for given id', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - assert.equal(browsingContext.id, id) - }) - - it('can create a window', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'window', - }) - assert.notEqual(browsingContext.id, null) - }) - - it('can create a window with a reference context', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'window', - referenceContext: await driver.getWindowHandle(), - }) - assert.notEqual(browsingContext.id, null) - }) - - it('can create a tab', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'tab', - }) - assert.notEqual(browsingContext.id, null) - }) - - it('can create a tab with a reference context', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'tab', - referenceContext: await driver.getWindowHandle(), - }) - assert.notEqual(browsingContext.id, null) - }) - - it('can navigate to a url', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'tab', - }) - - let info = await browsingContext.navigate(Pages.logEntryAdded) - - assert.notEqual(browsingContext.id, null) - assert.notEqual(info.navigationId, null) - assert(info.url.includes('/bidi/logEntryAdded.html')) - }) - - it('can navigate to a url with readiness state', async function () { - const browsingContext = await BrowsingContext(driver, { - type: 'tab', - }) - - const info = await browsingContext.navigate( - Pages.logEntryAdded, - 'complete' - ) - - assert.notEqual(browsingContext.id, null) - assert.notEqual(info.navigationId, null) - assert(info.url.includes('/bidi/logEntryAdded.html')) - }) - - it('can get tree with a child', async function () { - const browsingContextId = await driver.getWindowHandle() - const parentWindow = await BrowsingContext(driver, { - browsingContextId: browsingContextId, - }) - await parentWindow.navigate(Pages.iframePage, 'complete') - - const contextInfo = await parentWindow.getTree() - assert.equal(contextInfo.children.length, 1) - assert.equal(contextInfo.id, browsingContextId) - assert(contextInfo.children[0]['url'].includes('formPage.html')) - }) - - it('can get tree with depth', async function () { - const browsingContextId = await driver.getWindowHandle() - const parentWindow = await BrowsingContext(driver, { - browsingContextId: browsingContextId, - }) - await parentWindow.navigate(Pages.iframePage, 'complete') - - const contextInfo = await parentWindow.getTree(0) - assert.equal(contextInfo.children, null) - assert.equal(contextInfo.id, browsingContextId) - }) - - it('can close a window', async function () { - const window1 = await BrowsingContext(driver, { type: 'window' }) - const window2 = await BrowsingContext(driver, { type: 'window' }) - - await window2.close() - - assert.doesNotThrow(async function () { - await window1.getTree() - }) - await assert.rejects(window2.getTree(), { message: 'no such frame' }) - }) - - it('can print PDF with total pages', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.printPage) - const result = await browsingContext.printPage() - - let base64Code = result.data.slice(startIndex, endIndex) - assert.strictEqual(base64Code, pdfMagicNumber) - }) - - it('can print PDF with all valid parameters', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.printPage) - const result = await browsingContext.printPage({ - orientation: 'landscape', - scale: 1, - background: true, - width: 30, - height: 30, - top: 1, - bottom: 1, - left: 1, - right: 1, - shrinkToFit: true, - pageRanges: ['1-2'], - }) - - let base64Code = result.data.slice(startIndex, endIndex) - assert.strictEqual(base64Code, pdfMagicNumber) - }) - - it('can take screenshot', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - const response = await browsingContext.captureScreenshot() - const base64code = response.slice(startIndex, endIndex) - assert.equal(base64code, pngMagicNumber) - }) - - it('can take box screenshot', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - const response = await browsingContext.captureBoxScreenshot( - 5, - 5, - 10, - 10 - ) - - const base64code = response.slice(startIndex, endIndex) - assert.equal(base64code, pngMagicNumber) - }) - - it('can take element screenshot', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.formPage) - const element = await driver.findElement(By.id('checky')) - const elementId = await element.getId() - const response = await browsingContext.captureElementScreenshot( - elementId - ) - - const base64code = response.slice(startIndex, endIndex) - assert.equal(base64code, pngMagicNumber) - }) - - it('can scroll and take element screenshot', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.formPage) - const element = await driver.findElement(By.id('checkbox-with-label')) - const elementId = await element.getId() - const response = await browsingContext.captureElementScreenshot( - elementId, - undefined, - true - ) - - const base64code = response.slice(startIndex, endIndex) - assert.equal(base64code, pngMagicNumber) - }) - - it('can activate a browsing context', async function () { - const id = await driver.getWindowHandle() - const window1 = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await BrowsingContext(driver, { - type: 'window', - }) - - const result = await driver.executeScript('return document.hasFocus();') - - assert.equal(result, false) - - await window1.activate() - const result2 = await driver.executeScript( - 'return document.hasFocus();' - ) - - assert.equal(result2, true) - }) - - it('can handle user prompt', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.alertsPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - await browsingContext.handleUserPrompt() - - const result = await driver.getTitle() - - assert.equal(result, 'Testing Alerts') - }) - - it('can accept user prompt', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.alertsPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - await browsingContext.handleUserPrompt(true) - - const result = await driver.getTitle() - - assert.equal(result, 'Testing Alerts') - }) - - it('can dismiss user prompt', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.alertsPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - await browsingContext.handleUserPrompt(false) - - const result = await driver.getTitle() - - assert.equal(result, 'Testing Alerts') - }) - - it('can pass user text to user prompt', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.userpromptPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - const userText = 'Selenium automates browsers' - - await browsingContext.handleUserPrompt(undefined, userText) - - const result = await driver.getPageSource() - assert.equal(result.includes(userText), true) - }) - - it('can accept user prompt with user text', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.userpromptPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - const userText = 'Selenium automates browsers' - - await browsingContext.handleUserPrompt(true, userText) - - const result = await driver.getPageSource() - assert.equal(result.includes(userText), true) - }) - - it('can dismiss user prompt with user text', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.userpromptPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - const userText = 'Selenium automates browsers' - - await browsingContext.handleUserPrompt(false, userText) - - const result = await driver.getPageSource() - assert.equal(result.includes(userText), false) - }) - - xit('can reload a browsing context', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - const result = await browsingContext.navigate( - Pages.logEntryAdded, - 'complete' - ) - - await browsingContext.reload() - assert.equal(result.navigationId, null) - assert(result.url.includes('/bidi/logEntryAdded.html')) - }) - - xit('can reload with readiness state', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - const result = await browsingContext.navigate( - Pages.logEntryAdded, - 'complete' - ) - - await browsingContext.reload(undefined, 'complete') - assert.notEqual(result.navigationId, null) - assert(result.url.includes('/bidi/logEntryAdded.html')) - }) - - it('can set viewport', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.blankPage) - - await browsingContext.setViewport(250, 300) - - const result = await driver.executeScript( - 'return [window.innerWidth, window.innerHeight];' - ) - assert.equal(result[0], 250) - assert.equal(result[1], 300) - }) - - xit('can set viewport with device pixel ratio', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.blankPage) - - await browsingContext.setViewport(250, 300, 5) - - const result = await driver.executeScript( - 'return [window.innerWidth, window.innerHeight];' - ) - assert.equal(result[0], 250) - assert.equal(result[1], 300) - - const devicePixelRatio = await driver.executeScript( - 'return window.devicePixelRatio;' - ) - assert.equal(devicePixelRatio, 5) - }) - xit('can navigate back in the browser history', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.formPage) - - await driver.wait(until.elementLocated(By.id('imageButton')), 10000).submit() - await driver.wait(until.titleIs('We Arrive Here'), 5000) - - await browsingContext.back() - - await driver.wait(until.titleIs('We Leave From Here'), 5000) - }) - - xit('can navigate forward in the browser history', async function () { - const id = await driver.getWindowHandle() - const browsingContext = await BrowsingContext(driver, { - browsingContextId: id, - }) - - await driver.get(Pages.formPage) - - await driver.wait(until.elementLocated(By.id('imageButton')), 10000).submit() - await driver.wait(until.titleIs('We Arrive Here'), 5000) - - await browsingContext.back() - await driver.wait(until.titleIs('We Leave From Here'), 5000) - - await browsingContext.forward() - await driver.wait(until.titleIs('We Arrive Here'), 5000) - }) - }) - - describe('Browsing Context Inspector', function () { - it('can listen to window browsing context created event', async function () { - let contextInfo = null - const browsingcontextInspector = await BrowsingContextInspector(driver) - await browsingcontextInspector.onBrowsingContextCreated((entry) => { - contextInfo = entry - }) - - await driver.switchTo().newWindow('window') - const windowHandle = await driver.getWindowHandle() - assert.equal(contextInfo.id, windowHandle) - assert.equal(contextInfo.url, 'about:blank') - assert.equal(contextInfo.children, null) - assert.equal(contextInfo.parentBrowsingContext, null) - }) - - it('can listen to tab browsing context created event', async function () { - let contextInfo = null - const browsingcontextInspector = await BrowsingContextInspector(driver) - await browsingcontextInspector.onBrowsingContextCreated((entry) => { - contextInfo = entry - }) - - await driver.switchTo().newWindow('tab') - const tabHandle = await driver.getWindowHandle() - - assert.equal(contextInfo.id, tabHandle) - assert.equal(contextInfo.url, 'about:blank') - assert.equal(contextInfo.children, null) - assert.equal(contextInfo.parentBrowsingContext, null) - }) - - it('can listen to dom content loaded event', async function () { - const browsingcontextInspector = await BrowsingContextInspector(driver) - let navigationInfo = null - await browsingcontextInspector.onDomContentLoaded((entry) => { - navigationInfo = entry - }) - - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - await browsingContext.navigate(Pages.logEntryAdded, 'complete') - - assert.equal(navigationInfo.browsingContextId, browsingContext.id) - assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) - }) - - it('can listen to browsing context loaded event', async function () { - let navigationInfo = null - const browsingcontextInspector = await BrowsingContextInspector(driver) - - await browsingcontextInspector.onBrowsingContextLoaded((entry) => { - navigationInfo = entry - }) - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - await browsingContext.navigate(Pages.logEntryAdded, 'complete') - - assert.equal(navigationInfo.browsingContextId, browsingContext.id) - assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) - }) - - xit('can listen to navigation started event', async function () { - let navigationInfo = null - const browsingConextInspector = await BrowsingContextInspector(driver) - - await browsingConextInspector.onNavigationStarted((entry) => { - navigationInfo = entry - }) - - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - - await browsingContext.navigate(Pages.logEntryAdded, 'complete') - - assert.equal(navigationInfo.browsingContextId, browsingContext.id) - assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) - }) - - it('can listen to fragment navigated event', async function () { - let navigationInfo = null - const browsingConextInspector = await BrowsingContextInspector(driver) - - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - await browsingContext.navigate(Pages.linkedImage, 'complete') - - await browsingConextInspector.onFragmentNavigated((entry) => { - navigationInfo = entry - }) - - await browsingContext.navigate( - Pages.linkedImage + '#linkToAnchorOnThisPage', - 'complete' - ) - - assert.equal(navigationInfo.browsingContextId, browsingContext.id) - assert(navigationInfo.url.includes('linkToAnchorOnThisPage')) - }) - - xit('can listen to user prompt opened event', async function () { - let userpromptOpened = null - const browsingConextInspector = await BrowsingContextInspector(driver) - - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - - await driver.get(Pages.alertsPage) - - await driver.findElement(By.id('alert')).click() - - await driver.wait(until.alertIsPresent()) - - await browsingConextInspector.onUserPromptOpened((entry) => { - userpromptOpened = entry - }) - - assert.equal(userpromptOpened.browsingContextId, browsingContext.id) - assert.equal(userpromptOpened.type, 'alert') - }) - - xit('can listen to user prompt closed event', async function () { - let userpromptClosed = null - const browsingConextInspector = await BrowsingContextInspector(driver) - - const browsingContext = await BrowsingContext(driver, { - browsingContextId: await driver.getWindowHandle(), - }) - - await driver.get(Pages.alertsPage) - - await driver.findElement(By.id('prompt')).click() - - await driver.wait(until.alertIsPresent()) - - await browsingConextInspector.onUserPromptClosed((entry) => { - userpromptClosed = entry - }) - - await browsingContext.handleUserPrompt(true, 'selenium') - - assert.equal(userpromptClosed.browsingContextId, browsingContext.id) - assert.equal(userpromptClosed.accepted, true) - assert.equal(userpromptClosed.userText, 'selenium') - }) - }) - - describe('Local Value', function () { - it('can call function with undefined argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue(LocalValue.createUndefinedValue()) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==undefined)\n' + - ' throw Error("Argument should be undefined, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'undefined') - }) - - it('can call function with null argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue(LocalValue.createNullValue()) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==null)\n' + - ' throw Error("Argument should be null, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'null') - }) - - it('can call function with minus zero argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue( - LocalValue.createSpecialNumberValue(SpecialNumberType.MINUS_ZERO) - ) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==-0)\n' + - ' throw Error("Argument should be -0, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, '-0') - }) - - it('can call function with infinity argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue( - LocalValue.createSpecialNumberValue(SpecialNumberType.INFINITY) - ) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==Infinity)\n' + - ' throw Error("Argument should be Infinity, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, 'Infinity') - }) - - it('can call function with minus infinity argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue( - LocalValue.createSpecialNumberValue(SpecialNumberType.MINUS_INFINITY) - ) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==-Infinity)\n' + - ' throw Error("Argument should be -Infinity, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, '-Infinity') - }) - - it('can call function with number argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue(LocalValue.createNumberValue(1.4)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==1.4)\n' + - ' throw Error("Argument should be 1.4, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, 1.4) - }) - - it('can call function with boolean argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue(LocalValue.createBooleanValue(true)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==true)\n' + - ' throw Error("Argument should be true, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'boolean') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, true) - }) - - it('can call function with big int argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue(LocalValue.createBigIntValue('42')) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(arg!==42n)\n' + - ' throw Error("Argument should be 42n, but was "+arg);\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'bigint') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, '42') - }) - - it('can call function with array argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let arrayValue = [LocalValue.createStringValue('foobar')] - let value = new ArgumentValue(LocalValue.createArrayValue(arrayValue)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof Array))\n' + - ' throw Error("Argument type should be Array, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'array') - assert.notEqual(result.result.value, null) - - let resultValue = result.result.value - assert.equal(resultValue.length, 1) - assert.equal(resultValue[0].type, 'string') - assert.equal(resultValue[0].value, 'foobar') - }) - - it('can call function with set argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let setValue = [LocalValue.createStringValue('foobar')] - let value = new ArgumentValue(LocalValue.createSetValue(setValue)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof Set))\n' + - ' throw Error("Argument type should be Set, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'set') - assert.notEqual(result.result.value, null) - - let resultValue = result.result.value - assert.equal(resultValue.length, 1) - assert.equal(resultValue[0].type, 'string') - assert.equal(resultValue[0].value, 'foobar') - }) - - it('can call function with date argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue( - LocalValue.createDateValue('2022-05-31T13:47:29.000Z') - ) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof Date))\n' + - ' throw Error("Argument type should be Date, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'date') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, '2022-05-31T13:47:29.000Z') - }) - - it('can call function with map argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let mapValue = { foobar: LocalValue.createStringValue('foobar') } - let value = new ArgumentValue(LocalValue.createMapValue(mapValue)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof Map))\n' + - ' throw Error("Argument type should be Map, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'map') - assert.notEqual(result.result.value, null) - - let resultValue = result.result.value - - assert.equal(Object.keys(resultValue).length, 1) - assert.equal(resultValue['foobar'].type, 'string') - assert.equal(resultValue['foobar'].value, 'foobar') - }) - - it('can call function with object argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let mapValue = { foobar: LocalValue.createStringValue('foobar') } - let value = new ArgumentValue(LocalValue.createObjectValue(mapValue)) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof Object))\n' + - ' throw Error("Argument type should be Object, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'object') - assert.notEqual(result.result.value, null) - - let resultValue = result.result.value - assert.equal(Object.keys(resultValue).length, 1) - assert.equal(resultValue['foobar'].type, 'string') - assert.equal(resultValue['foobar'].value, 'foobar') - }) - - it('can call function with regex argument', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - let argumentValues = [] - let value = new ArgumentValue( - LocalValue.createRegularExpressionValue(new RegExpValue('foo', 'g')) - ) - argumentValues.push(value) - - const result = await manager.callFunctionInBrowsingContext( - id, - '(arg) => {{\n' + - ' if(! (arg instanceof RegExp))\n' + - ' throw Error("Argument type should be RegExp, but was "+\n' + - ' Object.prototype.toString.call(arg));\n' + - ' return arg;\n' + - ' }}', - false, - argumentValues - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'regexp') - assert.notEqual(result.result.value, null) - - let resultValue = result.result.value - assert.equal(resultValue.pattern, 'foo') - assert.equal(resultValue.flags, 'g') - }) - }) - - describe('Script Manager', function () { - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, 3) - }) - - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'array') - assert.notEqual(result.result.value, null) - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'string') - assert.notEqual(result.result.value, null) - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'promise') - assert.equal(result.result.value, undefined) - }) - - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - 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) - assert.notEqual(result.realmId, null) - assert.notEqual(result.result.handle, null) - assert.notEqual(result.result.value, null) - }) - - 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.notEqual(result.realmId, null) - - 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) - - // Make changes without sandbox - await manager.callFunctionInBrowsingContext( - id, - '() => { window.foo = 1; }', - true - ) - - // Check changes are not present in the sandbox - const resultNotInSandbox = await manager.callFunctionInBrowsingContext( - id, - '() => window.foo', - true, - null, - null, - null, - 'sandbox' - ) - - assert.equal(resultNotInSandbox.resultType, EvaluateResultType.SUCCESS) - assert.equal(resultNotInSandbox.result.type, 'undefined') - - // Make changes in the sandbox - - await manager.callFunctionInBrowsingContext( - id, - '() => { window.foo = 2; }', - true, - null, - null, - null, - 'sandbox' - ) - - // Check if the changes are present in the sandbox - - const resultInSandbox = await manager.callFunctionInBrowsingContext( - id, - '() => window.foo', - true, - null, - null, - null, - 'sandbox' - ) - - assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(resultInSandbox.realmId, null) - - assert.equal(resultInSandbox.result.type, 'number') - assert.notEqual(resultInSandbox.result.value, null) - assert.equal(resultInSandbox.result.value, 2) - }) - - 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 firstTabRealmId = realms[0].realmId - const secondTabRealmId = realms[1].realmId - - await manager.callFunctionInRealm( - firstTabRealmId, - '() => { window.foo = 3; }', - true - ) - - await manager.callFunctionInRealm( - secondTabRealmId, - '() => { window.foo = 5; }', - true - ) - - const firstContextResult = await manager.callFunctionInRealm( - firstTabRealmId, - '() => window.foo', - true - ) - - assert.equal(firstContextResult.resultType, EvaluateResultType.SUCCESS) - assert.equal(firstContextResult.result.type, 'number') - assert.notEqual(firstContextResult.result.value, null) - assert.equal(firstContextResult.result.value, 3) - - const secondContextResult = await manager.callFunctionInRealm( - secondTabRealmId, - '() => window.foo', - true - ) - - assert.equal(secondContextResult.resultType, EvaluateResultType.SUCCESS) - assert.equal(secondContextResult.result.type, 'number') - assert.notEqual(secondContextResult.result.value, null) - assert.equal(secondContextResult.result.value, 5) - }) - - 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.notEqual(result.realmId, null) - assert.equal(result.result.type, 'number') - assert.notEqual(result.result.value, null) - 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.notEqual(result.realmId, null) - - 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.realmId, null) - assert.equal(result.result.type, 'object') - assert.notEqual(result.result.value, null) - 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) - - // Make changes without sandbox - await manager.evaluateFunctionInBrowsingContext( - id, - 'window.foo = 1', - true - ) - - // Check changes are not present in the sandbox - const resultNotInSandbox = - await manager.evaluateFunctionInBrowsingContext( - id, - 'window.foo', - true, - null, - 'sandbox' - ) - - assert.equal(resultNotInSandbox.resultType, EvaluateResultType.SUCCESS) - assert.equal(resultNotInSandbox.result.type, 'undefined') - - // Make changes in the sandbox - 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.notEqual(resultInSandbox.realmId, null) - - assert.equal(resultInSandbox.result.type, 'number') - assert.notEqual(resultInSandbox.result.value, null) - 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 firstTabRealmId = realms[0].realmId - const secondTabRealmId = realms[1].realmId - - await manager.evaluateFunctionInRealm( - firstTabRealmId, - 'window.foo = 3', - true - ) - - await manager.evaluateFunctionInRealm( - secondTabRealmId, - 'window.foo = 5', - true - ) - - const firstContextResult = await manager.evaluateFunctionInRealm( - firstTabRealmId, - 'window.foo', - true - ) - - assert.equal(firstContextResult.resultType, EvaluateResultType.SUCCESS) - assert.equal(firstContextResult.result.type, 'number') - assert.notEqual(firstContextResult.result.value, null) - assert.equal(firstContextResult.result.value, 3) - - const secondContextResult = await manager.evaluateFunctionInRealm( - secondTabRealmId, - 'window.foo', - true - ) - - assert.equal(secondContextResult.resultType, EvaluateResultType.SUCCESS) - assert.equal(secondContextResult.result.type, 'number') - assert.notEqual(secondContextResult.result.value, null) - assert.equal(secondContextResult.result.value, 5) - }) - - it('can disown handles', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - const evaluateResult = await manager.evaluateFunctionInBrowsingContext( - id, - '({a:1})', - false, - ResultOwnership.ROOT - ) - - assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(evaluateResult.realmId, null) - assert.notEqual(evaluateResult.result.handle, null) - - let argumentValues = [] - let valueMap = evaluateResult.result.value - - let value1 = new ArgumentValue(LocalValue.createObjectValue(valueMap)) - let value2 = new ArgumentValue( - new ReferenceValue( - RemoteReferenceType.HANDLE, - evaluateResult.result.handle - ) - ) - argumentValues.push(value1) - argumentValues.push(value2) - - await manager.callFunctionInBrowsingContext( - id, - 'arg => arg.a', - false, - argumentValues - ) - - assert.notEqual(evaluateResult.result.value, null) - - let handles = [evaluateResult.result.handle] - await manager.disownBrowsingContextScript(id, handles) - - await manager - .callFunctionInBrowsingContext( - id, - 'arg => arg.a', - false, - argumentValues - ) - .catch((error) => { - assert(error instanceof TypeError) - }) - }) - - it('can disown handles in realm', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - const evaluateResult = await manager.evaluateFunctionInBrowsingContext( - id, - '({a:1})', - false, - ResultOwnership.ROOT - ) - - assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(evaluateResult.realmId, null) - assert.notEqual(evaluateResult.result.handle, null) - - let argumentValues = [] - let valueMap = evaluateResult.result.value - - let value1 = new ArgumentValue(LocalValue.createObjectValue(valueMap)) - let value2 = new ArgumentValue( - new ReferenceValue( - RemoteReferenceType.HANDLE, - evaluateResult.result.handle - ) - ) - argumentValues.push(value1) - argumentValues.push(value2) - - await manager.callFunctionInBrowsingContext( - id, - 'arg => arg.a', - false, - argumentValues - ) - - assert.notEqual(evaluateResult.result.value, null) - - let handles = [evaluateResult.result.handle] - await manager.disownRealmScript(evaluateResult.realmId, handles) - - await manager - .callFunctionInBrowsingContext( - id, - 'arg => arg.a', - false, - argumentValues - ) - .catch((error) => { - assert(error instanceof TypeError) - }) - }) - - 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) - - const firstWindowRealm = realms[0] - assert.equal(firstWindowRealm.realmType, RealmType.WINDOW) - assert.notEqual(firstWindowRealm.realmId, null) - assert.equal(firstWindowRealm.browsingContext, firstWindow) - - const secondWindowRealm = realms[1] - assert.equal(secondWindowRealm.realmType, RealmType.WINDOW) - assert.notEqual(secondWindowRealm.realmId, null) - assert.equal(secondWindowRealm.browsingContext, secondWindow) - }) - - 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) - - const firstWindowRealm = realms[0] - assert.equal(firstWindowRealm.realmType, RealmType.WINDOW) - assert.notEqual(firstWindowRealm.realmId, null) - assert.equal(firstWindowRealm.browsingContext, firstWindow) - - const secondWindowRealm = realms[1] - assert.equal(secondWindowRealm.realmType, RealmType.WINDOW) - assert.notEqual(secondWindowRealm.realmId, null) - assert.equal(secondWindowRealm.browsingContext, secondWindow) - }) - - 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) - assert.notEqual(tabRealm.realmId, null) - assert.equal(tabRealm.browsingContext, tabId) - }) - - 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) - assert.notEqual(windowRealm.realmId, null) - assert.equal(windowRealm.browsingContext, windowId) - }) - - it('can add preload script', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - await manager.addPreloadScript("() => { window.foo='bar'; }") - - // Check that preload script didn't apply the changes to the current context - let result = await manager.evaluateFunctionInBrowsingContext( - id, - 'window.foo', - true - ) - assert.equal(result.result.type, 'undefined') - - await driver.switchTo().newWindow('window') - const new_window_id = await driver.getWindowHandle() - - // Check that preload script applied the changes to the window - result = await manager.evaluateFunctionInBrowsingContext( - new_window_id, - 'window.foo', - true - ) - - assert.equal(result.resultType, EvaluateResultType.SUCCESS) - assert.notEqual(result.realmId, null) - assert.equal(result.result.type, 'string') - assert.notEqual(result.result.value, null) - assert.equal(result.result.value, 'bar') - - const browsingContext = await BrowsingContext(driver, { - type: 'tab', - }) - - await browsingContext.navigate(Pages.logEntryAdded, 'complete') - - // Check that preload script was applied after navigation - result = await manager.evaluateFunctionInBrowsingContext( - new_window_id, - 'window.foo', - true - ) - - assert.equal(result.result.type, 'string') - assert.equal(result.result.value, 'bar') - }) - - it('can add same preload script twice', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - const script_1 = await manager.addPreloadScript('() => { return 42; }') - const script_2 = await manager.addPreloadScript('() => { return 42; }') - - assert.notEqual(script_1, script_2) - }) - - it('can access preload script properties', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - await manager.addPreloadScript( - '() => { window.preloadScriptFunction = () => window.baz = 42; }' - ) - - await driver.switchTo().newWindow('tab') - const new_tab_id = await driver.getWindowHandle() - await driver.get(Pages.scriptTestAccessProperty) - - const result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.baz', - true - ) - - assert.equal(result.result.type, 'number') - assert.equal(result.result.value, 42) - }) - - it('can add preload script to sandbox', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - await manager.addPreloadScript('() => { window.foo = 1; }') - await manager.addPreloadScript( - '() => { window.bar = 2; }', - [], - 'sandbox' - ) - - await driver.switchTo().newWindow('tab') - const new_tab_id = await driver.getWindowHandle() - - let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.foo', - true, - null, - 'sandbox' - ) - - assert.equal(result_in_sandbox.result.type, 'undefined') - - let result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.bar', - true - ) - - assert.equal(result.result.type, 'undefined') - - result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( - new_tab_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 properties set by preload script', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - await manager.addPreloadScript('() => { window.foo = 42; }') - await manager.addPreloadScript( - '() => { window.foo = 50; }', - [], - 'sandbox_1' - ) - - await driver.switchTo().newWindow('tab') - const new_tab_id = await driver.getWindowHandle() - await driver.get(Pages.scriptTestRemoveProperty) - - let result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.foo', - true - ) - assert.equal(result.result.type, 'undefined') - - result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.foo', - true, - null, - 'sandbox_1' - ) - assert.equal(result.result.type, 'number') - assert.equal(result.result.value, 50) - }) - - it('can remove preload script', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - let script = await manager.addPreloadScript( - "() => { window.foo='bar'; }" - ) - - await driver.switchTo().newWindow('tab') - const tab_1_id = await driver.getWindowHandle() - - let result = await manager.evaluateFunctionInBrowsingContext( - tab_1_id, - 'window.foo', - true - ) - - assert.equal(result.result.type, 'string') - assert.equal(result.result.value, 'bar') - - await manager.removePreloadScript(script) - - await driver.switchTo().newWindow('tab') - const tab_2_id = await driver.getWindowHandle() - - // Check that changes from preload script were not applied after script was removed - result = await manager.evaluateFunctionInBrowsingContext( - tab_2_id, - 'window.foo', - true - ) - - assert.equal(result.result.type, 'undefined') - }) - - it('cannot remove same preload script twice', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - let script = await manager.addPreloadScript( - "() => { window.foo='bar'; }" - ) - - await manager.removePreloadScript(script) - - await manager.removePreloadScript(script).catch((error) => { - assert(error instanceof WebDriverError) - }) - }) - - it('can remove one of preload script', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - let script_1 = await manager.addPreloadScript( - "() => { window.bar='foo'; }" - ) - - let script_2 = await manager.addPreloadScript( - "() => { window.baz='bar'; }" - ) - - await manager.removePreloadScript(script_1) - - await driver.switchTo().newWindow('tab') - const new_tab_id = await driver.getWindowHandle() - - // Check that the first script didn't run - let result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.bar', - true - ) - - assert.equal(result.result.type, 'undefined') - - // Check that the second script still applied the changes to the window - result = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.baz', - true - ) - - assert.equal(result.result.type, 'string') - assert.equal(result.result.value, 'bar') - - // Clean up the second script - await manager.removePreloadScript(script_2) - }) - - it('can remove one of preload script from sandbox', async function () { - const id = await driver.getWindowHandle() - const manager = await ScriptManager(id, driver) - - let script_1 = await manager.addPreloadScript( - '() => { window.foo = 1; }' - ) - - let script_2 = await manager.addPreloadScript( - '() => { window.bar = 2; }', - [], - 'sandbox' - ) - - // Remove first preload script - await manager.removePreloadScript(script_1) - - // Remove second preload script - await manager.removePreloadScript(script_2) - - await driver.switchTo().newWindow('tab') - const new_tab_id = await driver.getWindowHandle() - - // Make sure that changes from first preload script were not applied - let result_in_window = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.foo', - true - ) - - assert.equal(result_in_window.result.type, 'undefined') - - // Make sure that changes from second preload script were not applied - let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( - new_tab_id, - 'window.bar', - true, - null, - 'sandbox' - ) - - assert.equal(result_in_sandbox.result.type, 'undefined') - }) - - 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(Pages.blankPage, 'complete') - - assert.notEqual(realmInfo, null) - assert.notEqual(realmInfo.realmId, null) - assert.equal(realmInfo.realmType, RealmType.WINDOW) - }) - }) - - describe('Network Inspector', function () { - it('can listen to event before request is sent', async function () { - let beforeRequestEvent = null - const inspector = await NetworkInspector(driver) - await inspector.beforeRequestSent(function (event) { - beforeRequestEvent = event - }) - - await driver.get(Pages.emptyPage) - - assert.equal(beforeRequestEvent.request.method, 'GET') - const url = beforeRequestEvent.request.url - assert.equal(url, await driver.getCurrentUrl()) - }) - - it('can request cookies', async function () { - const inspector = await NetworkInspector(driver) - let beforeRequestEvent = null - await inspector.beforeRequestSent(function (event) { - beforeRequestEvent = event - }) - - await driver.get(Pages.emptyText) - await driver.manage().addCookie({ - name: 'north', - value: 'biryani', - }) - await driver.navigate().refresh() - - assert.equal(beforeRequestEvent.request.method, 'GET') - assert.equal(beforeRequestEvent.request.cookies[0].name, 'north') - assert.equal( - beforeRequestEvent.request.cookies[0].value.value, - 'biryani' - ) - const url = beforeRequestEvent.request.url - assert.equal(url, await driver.getCurrentUrl()) - - await driver.manage().addCookie({ - name: 'south', - value: 'dosa', - }) - await driver.navigate().refresh() - - assert.equal(beforeRequestEvent.request.cookies[1].name, 'south') - assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa') - }) - - it('can redirect http equiv', async function () { - let beforeRequestEvent = [] - const inspector = await NetworkInspector(driver) - await inspector.beforeRequestSent(function (event) { - beforeRequestEvent.push(event) - }) - - await driver.get(Pages.redirectedHttpEquiv) - await driver.wait(until.urlContains('redirected.html'), 1000) - - assert.equal(beforeRequestEvent[0].request.method, 'GET') - assert( - beforeRequestEvent[0].request.url.includes( - 'redirected_http_equiv.html' - ) - ) - assert.equal(beforeRequestEvent[2].request.method, 'GET') - assert(beforeRequestEvent[2].request.url.includes('redirected.html')) - }) - - it('can subscribe to response started', async function () { - let onResponseStarted = [] - const inspector = await NetworkInspector(driver) - await inspector.responseStarted(function (event) { - onResponseStarted.push(event) - }) - - await driver.get(Pages.emptyText) - - assert.equal(onResponseStarted[0].request.method, 'GET') - assert.equal( - onResponseStarted[0].request.url, - await driver.getCurrentUrl() - ) - assert.equal( - onResponseStarted[0].response.url, - await driver.getCurrentUrl() - ) - assert.equal(onResponseStarted[0].response.fromCache, false) - assert(onResponseStarted[0].response.mimeType.includes('text/plain')) - assert.equal(onResponseStarted[0].response.status, 200) - assert.equal(onResponseStarted[0].response.statusText, 'OK') - }) - - it('test response started mime type', async function () { - let onResponseStarted = [] - const inspector = await NetworkInspector(driver) - await inspector.responseStarted(function (event) { - onResponseStarted.push(event) - }) - - // Checking mime type for 'html' text - await driver.get(Pages.emptyPage) - assert.equal(onResponseStarted[0].request.method, 'GET') - assert.equal( - onResponseStarted[0].request.url, - await driver.getCurrentUrl() - ) - assert.equal( - onResponseStarted[0].response.url, - await driver.getCurrentUrl() - ) - assert(onResponseStarted[0].response.mimeType.includes('text/html')) - - // Checking mime type for 'plain' text - onResponseStarted = [] - await driver.get(Pages.emptyText) - assert.equal( - onResponseStarted[0].response.url, - await driver.getCurrentUrl() - ) - assert(onResponseStarted[0].response.mimeType.includes('text/plain')) - }) - - it('can subscribe to response completed', async function () { - let onResponseCompleted = [] - const inspector = await NetworkInspector(driver) - await inspector.responseCompleted(function (event) { - onResponseCompleted.push(event) - }) - - await driver.get(Pages.emptyPage) - - assert.equal(onResponseCompleted[0].request.method, 'GET') - assert.equal( - onResponseCompleted[0].request.url, - await driver.getCurrentUrl() - ) - assert.equal( - onResponseCompleted[0].response.url, - await driver.getCurrentUrl() - ) - assert.equal(onResponseCompleted[0].response.fromCache, false) - assert(onResponseCompleted[0].response.mimeType.includes('text/html')) - assert.equal(onResponseCompleted[0].response.status, 200) - assert.equal(onResponseCompleted[0].response.statusText, 'OK') - assert.equal(onResponseCompleted[0].redirectCount, 0) - }) - - it('test response completed mime type', async function () { - let onResponseCompleted = [] - const inspector = await NetworkInspector(driver) - await inspector.responseCompleted(function (event) { - onResponseCompleted.push(event) - }) - - // Checking mime type for 'html' text - await driver.get(Pages.emptyPage) - assert.equal(onResponseCompleted[0].request.method, 'GET') - assert.equal( - onResponseCompleted[0].request.url, - await driver.getCurrentUrl() - ) - assert.equal( - onResponseCompleted[0].response.url, - await driver.getCurrentUrl() - ) - assert(onResponseCompleted[0].response.mimeType.includes('text/html')) - - // Checking mime type for 'plain' text - onResponseCompleted = [] - await driver.get(Pages.emptyText) - assert.equal( - onResponseCompleted[0].response.url, - await driver.getCurrentUrl() - ) - assert(onResponseCompleted[0].response.mimeType.includes('text/plain')) - }) - // Implemented in Firefox Nightly 123 - xit('can subscribe to auth required', async function () { - let onAuthRequired = [] - const inspector = await NetworkInspector(driver) - await inspector.authRequired(function (event) { - onAuthRequired.push(event) - }) - - await driver.get(Pages.basicAuth) - - assert.equal(onAuthRequired[0].request.method, 'GET') - assert.equal( - onAuthRequired[0].request.url, - await driver.getCurrentUrl() - ) - assert.equal( - onAuthRequired[0].response.url, - await driver.getCurrentUrl() - ) - assert.equal(onAuthRequired[0].response.fromCache, false) - assert(onAuthRequired[0].response.mimeType.includes('text/plain')) - assert.equal(onAuthRequired[0].response.status, 401) - assert.equal(onAuthRequired[0].response.statusText, 'unauthorized') - }) - }) - describe('Integration Tests', function () { it('can navigate and listen to errors', async function () { let logEntry = null diff --git a/javascript/node/selenium-webdriver/test/bidi/browsingcontext_inspector_test.js b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_inspector_test.js new file mode 100644 index 00000000000000..7222872f171ec3 --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_inspector_test.js @@ -0,0 +1,196 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser, By, WebElement} = require('../../') +const {Pages, suite} = require('../../lib/test') +const BrowsingContext = require('../../bidi/browsingContext') +const BrowsingContextInspector = require('../../bidi/browsingContextInspector') +const until = require('../../lib/until') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Browsing Context Inspector', function () { + it('can listen to window browsing context created event', async function () { + let contextInfo = null + const browsingcontextInspector = await BrowsingContextInspector(driver) + await browsingcontextInspector.onBrowsingContextCreated((entry) => { + contextInfo = entry + }) + + await driver.switchTo().newWindow('window') + const windowHandle = await driver.getWindowHandle() + assert.equal(contextInfo.id, windowHandle) + assert.equal(contextInfo.url, 'about:blank') + assert.equal(contextInfo.children, null) + assert.equal(contextInfo.parentBrowsingContext, null) + }) + + it('can listen to tab browsing context created event', async function () { + let contextInfo = null + const browsingcontextInspector = await BrowsingContextInspector(driver) + await browsingcontextInspector.onBrowsingContextCreated((entry) => { + contextInfo = entry + }) + + await driver.switchTo().newWindow('tab') + const tabHandle = await driver.getWindowHandle() + + assert.equal(contextInfo.id, tabHandle) + assert.equal(contextInfo.url, 'about:blank') + assert.equal(contextInfo.children, null) + assert.equal(contextInfo.parentBrowsingContext, null) + }) + + it('can listen to dom content loaded event', async function () { + const browsingcontextInspector = await BrowsingContextInspector(driver) + let navigationInfo = null + await browsingcontextInspector.onDomContentLoaded((entry) => { + navigationInfo = entry + }) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can listen to browsing context loaded event', async function () { + let navigationInfo = null + const browsingcontextInspector = await BrowsingContextInspector(driver) + + await browsingcontextInspector.onBrowsingContextLoaded((entry) => { + navigationInfo = entry + }) + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) + }) + + xit('can listen to navigation started event', async function () { + let navigationInfo = null + const browsingConextInspector = await BrowsingContextInspector(driver) + + await browsingConextInspector.onNavigationStarted((entry) => { + navigationInfo = entry + }) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can listen to fragment navigated event', async function () { + let navigationInfo = null + const browsingConextInspector = await BrowsingContextInspector(driver) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + await browsingContext.navigate(Pages.linkedImage, 'complete') + + await browsingConextInspector.onFragmentNavigated((entry) => { + navigationInfo = entry + }) + + await browsingContext.navigate( + Pages.linkedImage + '#linkToAnchorOnThisPage', + 'complete' + ) + + assert.equal(navigationInfo.browsingContextId, browsingContext.id) + assert(navigationInfo.url.includes('linkToAnchorOnThisPage')) + }) + + xit('can listen to user prompt opened event', async function () { + let userpromptOpened = null + const browsingConextInspector = await BrowsingContextInspector(driver) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + + await driver.get(Pages.alertsPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + await browsingConextInspector.onUserPromptOpened((entry) => { + userpromptOpened = entry + }) + + assert.equal(userpromptOpened.browsingContextId, browsingContext.id) + assert.equal(userpromptOpened.type, 'alert') + }) + + xit('can listen to user prompt closed event', async function () { + let userpromptClosed = null + const browsingConextInspector = await BrowsingContextInspector(driver) + + const browsingContext = await BrowsingContext(driver, { + browsingContextId: await driver.getWindowHandle(), + }) + + await driver.get(Pages.alertsPage) + + await driver.findElement(By.id('prompt')).click() + + await driver.wait(until.alertIsPresent()) + + await browsingConextInspector.onUserPromptClosed((entry) => { + userpromptClosed = entry + }) + + await browsingContext.handleUserPrompt(true, 'selenium') + + assert.equal(userpromptClosed.browsingContextId, browsingContext.id) + assert.equal(userpromptClosed.accepted, true) + assert.equal(userpromptClosed.userText, 'selenium') + }) + }) + }, + {browsers: [Browser.FIREFOX]} +) diff --git a/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js new file mode 100644 index 00000000000000..6c584c1274e8f9 --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js @@ -0,0 +1,464 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser, By, WebElement} = require('../../') +const {Pages, suite} = require('../../lib/test') +const BrowsingContext = require('../../bidi/browsingContext') +const until = require('../../lib/until') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Browsing Context', function () { + let startIndex = 0 + let endIndex = 5 + let pdfMagicNumber = 'JVBER' + let pngMagicNumber = 'iVBOR' + + it('can create a browsing context for given id', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + assert.equal(browsingContext.id, id) + }) + + it('can create a window', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'window', + }) + assert.notEqual(browsingContext.id, null) + }) + + it('can create a window with a reference context', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'window', + referenceContext: await driver.getWindowHandle(), + }) + assert.notEqual(browsingContext.id, null) + }) + + it('can create a tab', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'tab', + }) + assert.notEqual(browsingContext.id, null) + }) + + it('can create a tab with a reference context', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'tab', + referenceContext: await driver.getWindowHandle(), + }) + assert.notEqual(browsingContext.id, null) + }) + + it('can navigate to a url', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'tab', + }) + + let info = await browsingContext.navigate(Pages.logEntryAdded) + + assert.notEqual(browsingContext.id, null) + assert.notEqual(info.navigationId, null) + assert(info.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can navigate to a url with readiness state', async function () { + const browsingContext = await BrowsingContext(driver, { + type: 'tab', + }) + + const info = await browsingContext.navigate( + Pages.logEntryAdded, + 'complete' + ) + + assert.notEqual(browsingContext.id, null) + assert.notEqual(info.navigationId, null) + assert(info.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can get tree with a child', async function () { + const browsingContextId = await driver.getWindowHandle() + const parentWindow = await BrowsingContext(driver, { + browsingContextId: browsingContextId, + }) + await parentWindow.navigate(Pages.iframePage, 'complete') + + const contextInfo = await parentWindow.getTree() + assert.equal(contextInfo.children.length, 1) + assert.equal(contextInfo.id, browsingContextId) + assert(contextInfo.children[0]['url'].includes('formPage.html')) + }) + + it('can get tree with depth', async function () { + const browsingContextId = await driver.getWindowHandle() + const parentWindow = await BrowsingContext(driver, { + browsingContextId: browsingContextId, + }) + await parentWindow.navigate(Pages.iframePage, 'complete') + + const contextInfo = await parentWindow.getTree(0) + assert.equal(contextInfo.children, null) + assert.equal(contextInfo.id, browsingContextId) + }) + + it('can close a window', async function () { + const window1 = await BrowsingContext(driver, {type: 'window'}) + const window2 = await BrowsingContext(driver, {type: 'window'}) + + await window2.close() + + assert.doesNotThrow(async function () { + await window1.getTree() + }) + await assert.rejects(window2.getTree(), {message: 'no such frame'}) + }) + + it('can print PDF with total pages', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.printPage) + const result = await browsingContext.printPage() + + let base64Code = result.data.slice(startIndex, endIndex) + assert.strictEqual(base64Code, pdfMagicNumber) + }) + + it('can print PDF with all valid parameters', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.printPage) + const result = await browsingContext.printPage({ + orientation: 'landscape', + scale: 1, + background: true, + width: 30, + height: 30, + top: 1, + bottom: 1, + left: 1, + right: 1, + shrinkToFit: true, + pageRanges: ['1-2'], + }) + + let base64Code = result.data.slice(startIndex, endIndex) + assert.strictEqual(base64Code, pdfMagicNumber) + }) + + it('can take screenshot', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + const response = await browsingContext.captureScreenshot() + const base64code = response.slice(startIndex, endIndex) + assert.equal(base64code, pngMagicNumber) + }) + + it('can take box screenshot', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + const response = await browsingContext.captureBoxScreenshot( + 5, + 5, + 10, + 10 + ) + + const base64code = response.slice(startIndex, endIndex) + assert.equal(base64code, pngMagicNumber) + }) + + it('can take element screenshot', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.formPage) + const element = await driver.findElement(By.id('checky')) + const elementId = await element.getId() + const response = await browsingContext.captureElementScreenshot( + elementId + ) + + const base64code = response.slice(startIndex, endIndex) + assert.equal(base64code, pngMagicNumber) + }) + + it('can scroll and take element screenshot', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.formPage) + const element = await driver.findElement(By.id('checkbox-with-label')) + const elementId = await element.getId() + const response = await browsingContext.captureElementScreenshot( + elementId, + undefined, + true + ) + + const base64code = response.slice(startIndex, endIndex) + assert.equal(base64code, pngMagicNumber) + }) + + it('can activate a browsing context', async function () { + const id = await driver.getWindowHandle() + const window1 = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await BrowsingContext(driver, { + type: 'window', + }) + + const result = await driver.executeScript('return document.hasFocus();') + + assert.equal(result, false) + + await window1.activate() + const result2 = await driver.executeScript( + 'return document.hasFocus();' + ) + + assert.equal(result2, true) + }) + + it('can handle user prompt', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.alertsPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + await browsingContext.handleUserPrompt() + + const result = await driver.getTitle() + + assert.equal(result, 'Testing Alerts') + }) + + it('can accept user prompt', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.alertsPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + await browsingContext.handleUserPrompt(true) + + const result = await driver.getTitle() + + assert.equal(result, 'Testing Alerts') + }) + + it('can dismiss user prompt', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.alertsPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + await browsingContext.handleUserPrompt(false) + + const result = await driver.getTitle() + + assert.equal(result, 'Testing Alerts') + }) + + it('can pass user text to user prompt', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.userpromptPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + const userText = 'Selenium automates browsers' + + await browsingContext.handleUserPrompt(undefined, userText) + + const result = await driver.getPageSource() + assert.equal(result.includes(userText), true) + }) + + it('can accept user prompt with user text', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.userpromptPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + const userText = 'Selenium automates browsers' + + await browsingContext.handleUserPrompt(true, userText) + + const result = await driver.getPageSource() + assert.equal(result.includes(userText), true) + }) + + it('can dismiss user prompt with user text', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.userpromptPage) + + await driver.findElement(By.id('alert')).click() + + await driver.wait(until.alertIsPresent()) + + const userText = 'Selenium automates browsers' + + await browsingContext.handleUserPrompt(false, userText) + + const result = await driver.getPageSource() + assert.equal(result.includes(userText), false) + }) + + xit('can reload a browsing context', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + const result = await browsingContext.navigate( + Pages.logEntryAdded, + 'complete' + ) + + await browsingContext.reload() + assert.equal(result.navigationId, null) + assert(result.url.includes('/bidi/logEntryAdded.html')) + }) + + xit('can reload with readiness state', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + const result = await browsingContext.navigate( + Pages.logEntryAdded, + 'complete' + ) + + await browsingContext.reload(undefined, 'complete') + assert.notEqual(result.navigationId, null) + assert(result.url.includes('/bidi/logEntryAdded.html')) + }) + + it('can set viewport', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.blankPage) + + await browsingContext.setViewport(250, 300) + + const result = await driver.executeScript( + 'return [window.innerWidth, window.innerHeight];' + ) + assert.equal(result[0], 250) + assert.equal(result[1], 300) + }) + + xit('can set viewport with device pixel ratio', async function () { + const id = await driver.getWindowHandle() + const browsingContext = await BrowsingContext(driver, { + browsingContextId: id, + }) + + await driver.get(Pages.blankPage) + + await browsingContext.setViewport(250, 300, 5) + + const result = await driver.executeScript( + 'return [window.innerWidth, window.innerHeight];' + ) + assert.equal(result[0], 250) + assert.equal(result[1], 300) + + const devicePixelRatio = await driver.executeScript( + 'return window.devicePixelRatio;' + ) + assert.equal(devicePixelRatio, 5) + }) + }) + }, + {browsers: [Browser.FIREFOX]} +) diff --git a/javascript/node/selenium-webdriver/test/bidi/local_value_test.js b/javascript/node/selenium-webdriver/test/bidi/local_value_test.js new file mode 100644 index 00000000000000..34dcfc1d7d709e --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/local_value_test.js @@ -0,0 +1,438 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser} = require('../../') +const {suite} = require('../../lib/test') + +const ScriptManager = require('../../bidi/scriptManager') +const { + LocalValue, + RegExpValue, +} = require('../../bidi/protocolValue') +const {ArgumentValue} = require('../../bidi/argumentValue') +const {EvaluateResultType} = require('../../bidi/evaluateResult') +const {SpecialNumberType} = require('../../bidi/protocolType') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Local Value', function () { + it('can call function with undefined argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue(LocalValue.createUndefinedValue()) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==undefined)\n' + + ' throw Error("Argument should be undefined, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'undefined') + }) + + it('can call function with null argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue(LocalValue.createNullValue()) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==null)\n' + + ' throw Error("Argument should be null, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'null') + }) + + it('can call function with minus zero argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue( + LocalValue.createSpecialNumberValue(SpecialNumberType.MINUS_ZERO) + ) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==-0)\n' + + ' throw Error("Argument should be -0, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, '-0') + }) + + it('can call function with infinity argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue( + LocalValue.createSpecialNumberValue(SpecialNumberType.INFINITY) + ) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==Infinity)\n' + + ' throw Error("Argument should be Infinity, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, 'Infinity') + }) + + it('can call function with minus infinity argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue( + LocalValue.createSpecialNumberValue(SpecialNumberType.MINUS_INFINITY) + ) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==-Infinity)\n' + + ' throw Error("Argument should be -Infinity, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, '-Infinity') + }) + + it('can call function with number argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue(LocalValue.createNumberValue(1.4)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==1.4)\n' + + ' throw Error("Argument should be 1.4, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, 1.4) + }) + + it('can call function with boolean argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue(LocalValue.createBooleanValue(true)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==true)\n' + + ' throw Error("Argument should be true, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'boolean') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, true) + }) + + it('can call function with big int argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue(LocalValue.createBigIntValue('42')) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(arg!==42n)\n' + + ' throw Error("Argument should be 42n, but was "+arg);\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'bigint') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, '42') + }) + + it('can call function with array argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let arrayValue = [LocalValue.createStringValue('foobar')] + let value = new ArgumentValue(LocalValue.createArrayValue(arrayValue)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof Array))\n' + + ' throw Error("Argument type should be Array, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'array') + assert.notEqual(result.result.value, null) + + let resultValue = result.result.value + assert.equal(resultValue.length, 1) + assert.equal(resultValue[0].type, 'string') + assert.equal(resultValue[0].value, 'foobar') + }) + + it('can call function with set argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let setValue = [LocalValue.createStringValue('foobar')] + let value = new ArgumentValue(LocalValue.createSetValue(setValue)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof Set))\n' + + ' throw Error("Argument type should be Set, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'set') + assert.notEqual(result.result.value, null) + + let resultValue = result.result.value + assert.equal(resultValue.length, 1) + assert.equal(resultValue[0].type, 'string') + assert.equal(resultValue[0].value, 'foobar') + }) + + it('can call function with date argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue( + LocalValue.createDateValue('2022-05-31T13:47:29.000Z') + ) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof Date))\n' + + ' throw Error("Argument type should be Date, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'date') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, '2022-05-31T13:47:29.000Z') + }) + + it('can call function with map argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let mapValue = {foobar: LocalValue.createStringValue('foobar')} + let value = new ArgumentValue(LocalValue.createMapValue(mapValue)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof Map))\n' + + ' throw Error("Argument type should be Map, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'map') + assert.notEqual(result.result.value, null) + + let resultValue = result.result.value + + assert.equal(Object.keys(resultValue).length, 1) + assert.equal(resultValue['foobar'].type, 'string') + assert.equal(resultValue['foobar'].value, 'foobar') + }) + + it('can call function with object argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let mapValue = {foobar: LocalValue.createStringValue('foobar')} + let value = new ArgumentValue(LocalValue.createObjectValue(mapValue)) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof Object))\n' + + ' throw Error("Argument type should be Object, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'object') + assert.notEqual(result.result.value, null) + + let resultValue = result.result.value + assert.equal(Object.keys(resultValue).length, 1) + assert.equal(resultValue['foobar'].type, 'string') + assert.equal(resultValue['foobar'].value, 'foobar') + }) + + it('can call function with regex argument', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + let argumentValues = [] + let value = new ArgumentValue( + LocalValue.createRegularExpressionValue(new RegExpValue('foo', 'g')) + ) + argumentValues.push(value) + + const result = await manager.callFunctionInBrowsingContext( + id, + '(arg) => {{\n' + + ' if(! (arg instanceof RegExp))\n' + + ' throw Error("Argument type should be RegExp, but was "+\n' + + ' Object.prototype.toString.call(arg));\n' + + ' return arg;\n' + + ' }}', + false, + argumentValues + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'regexp') + assert.notEqual(result.result.value, null) + + let resultValue = result.result.value + assert.equal(resultValue.pattern, 'foo') + assert.equal(resultValue.flags, 'g') + }) + }) + }, + {browsers: [Browser.FIREFOX]} +) diff --git a/javascript/node/selenium-webdriver/test/bidi/log_inspector_test.js b/javascript/node/selenium-webdriver/test/bidi/log_inspector_test.js new file mode 100644 index 00000000000000..440d10a78aeebb --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/log_inspector_test.js @@ -0,0 +1,271 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser} = require('../../') +const {Pages, suite} = require('../../lib/test') +const logInspector = require('../../bidi/logInspector') +const filterBy = require('../../bidi/filterBy') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Log Inspector', function () { + it('can listen to console log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onConsoleEntry(function (log) { + logEntry = log + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry.text, 'Hello, world!') + assert.equal(logEntry.realm, null) + assert.equal(logEntry.type, 'console') + assert.equal(logEntry.level, 'info') + assert.equal(logEntry.method, 'log') + assert.equal(logEntry.stackTrace, null) + assert.equal(logEntry.args.length, 1) + + await inspector.close() + }) + + it('can listen to console log with different consumers', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onConsoleEntry(function (log) { + logEntry = log + }) + + let logEntryText = null + await inspector.onConsoleEntry(function (log) { + logEntryText = log.text + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry.text, 'Hello, world!') + assert.equal(logEntry.realm, null) + assert.equal(logEntry.type, 'console') + assert.equal(logEntry.level, 'info') + assert.equal(logEntry.method, 'log') + assert.equal(logEntry.stackTrace, null) + assert.equal(logEntry.args.length, 1) + + assert.equal(logEntryText, 'Hello, world!') + + await inspector.close() + }) + + it('can filter console info level log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onConsoleEntry(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('info')) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry.text, 'Hello, world!') + assert.equal(logEntry.realm, null) + assert.equal(logEntry.type, 'console') + assert.equal(logEntry.level, 'info') + assert.equal(logEntry.method, 'log') + assert.equal(logEntry.stackTrace, null) + assert.equal(logEntry.args.length, 1) + + await inspector.close() + }) + + it('can filter console log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onConsoleEntry(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('error')) + + await driver.get(Pages.logEntryAdded) + // Generating info level log but we are filtering by error level + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry, null) + await inspector.close() + }) + + it('can listen to javascript log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onJavascriptLog(function (log) { + logEntry = log + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + assert.equal(logEntry.text, 'Error: Not working') + assert.equal(logEntry.type, 'javascript') + assert.equal(logEntry.level, 'error') + + await inspector.close() + }) + + it('can filter javascript log at error level', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onJavascriptLog(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('error')) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + assert.equal(logEntry.text, 'Error: Not working') + assert.equal(logEntry.type, 'javascript') + assert.equal(logEntry.level, 'error') + + await inspector.close() + }) + + it('can filter javascript log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onJavascriptLog(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('info')) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + assert.equal(logEntry, null) + + await inspector.close() + }) + + it('can listen to javascript error log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onJavascriptException(function (log) { + logEntry = log + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + assert.equal(logEntry.text, 'Error: Not working') + assert.equal(logEntry.type, 'javascript') + assert.equal(logEntry.level, 'error') + + await inspector.close() + }) + + it('can retrieve stack trace for a log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onJavascriptException(function (log) { + logEntry = log + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + const stackTrace = logEntry.stackTrace + assert.notEqual(stackTrace, null) + assert.equal(stackTrace.callFrames.length, 3) + + await inspector.close() + }) + + it('can listen to any log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onLog(function (log) { + logEntry = log + }) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry.text, 'Hello, world!') + assert.equal(logEntry.realm, null) + assert.equal(logEntry.type, 'console') + assert.equal(logEntry.level, 'info') + assert.equal(logEntry.method, 'log') + assert.equal(logEntry.stackTrace, null) + assert.equal(logEntry.args.length, 1) + + await inspector.close() + }) + + it('can filter any log', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onLog(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('info')) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'consoleLog'}).click() + + assert.equal(logEntry.text, 'Hello, world!') + assert.equal(logEntry.realm, null) + assert.equal(logEntry.type, 'console') + assert.equal(logEntry.level, 'info') + assert.equal(logEntry.method, 'log') + assert.equal(logEntry.stackTrace, null) + assert.equal(logEntry.args.length, 1) + + await inspector.close() + }) + + it('can filter any log at error level', async function () { + let logEntry = null + const inspector = await logInspector(driver) + await inspector.onLog(function (log) { + logEntry = log + }, filterBy.FilterBy.logLevel('error')) + + await driver.get(Pages.logEntryAdded) + await driver.findElement({id: 'jsException'}).click() + + assert.equal(logEntry.text, 'Error: Not working') + assert.equal(logEntry.type, 'javascript') + assert.equal(logEntry.level, 'error') + await inspector.close() + }) + }) + }, + {browsers: [Browser.FIREFOX]} +) diff --git a/javascript/node/selenium-webdriver/test/bidi/network_test.js b/javascript/node/selenium-webdriver/test/bidi/network_test.js new file mode 100644 index 00000000000000..a91437d066b4b4 --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/network_test.js @@ -0,0 +1,222 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const { Browser, By, WebElement } = require('../../') +const { Pages, suite } = require('../../lib/test') +const NetworkInspector = require('../../bidi/networkInspector') +const until = require('../../lib/until') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Network Inspector', function () { + it('can listen to event before request is sent', async function () { + let beforeRequestEvent = null + const inspector = await NetworkInspector(driver) + await inspector.beforeRequestSent(function (event) { + beforeRequestEvent = event + }) + + await driver.get(Pages.emptyPage) + + assert.equal(beforeRequestEvent.request.method, 'GET') + const url = beforeRequestEvent.request.url + assert.equal(url, await driver.getCurrentUrl()) + }) + + it('can request cookies', async function () { + const inspector = await NetworkInspector(driver) + let beforeRequestEvent = null + await inspector.beforeRequestSent(function (event) { + beforeRequestEvent = event + }) + + await driver.get(Pages.emptyText) + await driver.manage().addCookie({ + name: 'north', + value: 'biryani', + }) + await driver.navigate().refresh() + + assert.equal(beforeRequestEvent.request.method, 'GET') + assert.equal(beforeRequestEvent.request.cookies[0].name, 'north') + assert.equal( + beforeRequestEvent.request.cookies[0].value.value, + 'biryani' + ) + const url = beforeRequestEvent.request.url + assert.equal(url, await driver.getCurrentUrl()) + + await driver.manage().addCookie({ + name: 'south', + value: 'dosa', + }) + await driver.navigate().refresh() + + assert.equal(beforeRequestEvent.request.cookies[1].name, 'south') + assert.equal(beforeRequestEvent.request.cookies[1].value.value, 'dosa') + }) + + it('can redirect http equiv', async function () { + let beforeRequestEvent = [] + const inspector = await NetworkInspector(driver) + await inspector.beforeRequestSent(function (event) { + beforeRequestEvent.push(event) + }) + + await driver.get(Pages.redirectedHttpEquiv) + await driver.wait(until.urlContains('redirected.html'), 1000) + + assert.equal(beforeRequestEvent[0].request.method, 'GET') + assert( + beforeRequestEvent[0].request.url.includes( + 'redirected_http_equiv.html' + ) + ) + assert.equal(beforeRequestEvent[2].request.method, 'GET') + assert(beforeRequestEvent[2].request.url.includes('redirected.html')) + }) + + it('can subscribe to response started', async function () { + let onResponseStarted = [] + const inspector = await NetworkInspector(driver) + await inspector.responseStarted(function (event) { + onResponseStarted.push(event) + }) + + await driver.get(Pages.emptyText) + + assert.equal(onResponseStarted[0].request.method, 'GET') + assert.equal( + onResponseStarted[0].request.url, + await driver.getCurrentUrl() + ) + assert.equal( + onResponseStarted[0].response.url, + await driver.getCurrentUrl() + ) + assert.equal(onResponseStarted[0].response.fromCache, false) + assert(onResponseStarted[0].response.mimeType.includes('text/plain')) + assert.equal(onResponseStarted[0].response.status, 200) + assert.equal(onResponseStarted[0].response.statusText, 'OK') + }) + + it('test response started mime type', async function () { + let onResponseStarted = [] + const inspector = await NetworkInspector(driver) + await inspector.responseStarted(function (event) { + onResponseStarted.push(event) + }) + + // Checking mime type for 'html' text + await driver.get(Pages.emptyPage) + assert.equal(onResponseStarted[0].request.method, 'GET') + assert.equal( + onResponseStarted[0].request.url, + await driver.getCurrentUrl() + ) + assert.equal( + onResponseStarted[0].response.url, + await driver.getCurrentUrl() + ) + assert(onResponseStarted[0].response.mimeType.includes('text/html')) + + // Checking mime type for 'plain' text + onResponseStarted = [] + await driver.get(Pages.emptyText) + assert.equal( + onResponseStarted[0].response.url, + await driver.getCurrentUrl() + ) + assert(onResponseStarted[0].response.mimeType.includes('text/plain')) + }) + + it('can subscribe to response completed', async function () { + let onResponseCompleted = [] + const inspector = await NetworkInspector(driver) + await inspector.responseCompleted(function (event) { + onResponseCompleted.push(event) + }) + + await driver.get(Pages.emptyPage) + + assert.equal(onResponseCompleted[0].request.method, 'GET') + assert.equal( + onResponseCompleted[0].request.url, + await driver.getCurrentUrl() + ) + assert.equal( + onResponseCompleted[0].response.url, + await driver.getCurrentUrl() + ) + assert.equal(onResponseCompleted[0].response.fromCache, false) + assert(onResponseCompleted[0].response.mimeType.includes('text/html')) + assert.equal(onResponseCompleted[0].response.status, 200) + assert.equal(onResponseCompleted[0].response.statusText, 'OK') + assert.equal(onResponseCompleted[0].redirectCount, 0) + }) + + it('test response completed mime type', async function () { + let onResponseCompleted = [] + const inspector = await NetworkInspector(driver) + await inspector.responseCompleted(function (event) { + onResponseCompleted.push(event) + }) + + // Checking mime type for 'html' text + await driver.get(Pages.emptyPage) + assert.equal(onResponseCompleted[0].request.method, 'GET') + assert.equal( + onResponseCompleted[0].request.url, + await driver.getCurrentUrl() + ) + assert.equal( + onResponseCompleted[0].response.url, + await driver.getCurrentUrl() + ) + assert(onResponseCompleted[0].response.mimeType.includes('text/html')) + + // Checking mime type for 'plain' text + onResponseCompleted = [] + await driver.get(Pages.emptyText) + assert.equal( + onResponseCompleted[0].response.url, + await driver.getCurrentUrl() + ) + assert(onResponseCompleted[0].response.mimeType.includes('text/plain')) + }) + }) + + }, + { browsers: [Browser.FIREFOX] } +) diff --git a/javascript/node/selenium-webdriver/test/bidi/script_test.js b/javascript/node/selenium-webdriver/test/bidi/script_test.js new file mode 100644 index 00000000000000..200ecf21f64135 --- /dev/null +++ b/javascript/node/selenium-webdriver/test/bidi/script_test.js @@ -0,0 +1,995 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +'use strict' + +const assert = require('assert') +const firefox = require('../../firefox') +const {Browser, By, WebElement} = require('../../') +const {Pages, suite} = require('../../lib/test') +const BrowsingContext = require('../../bidi/browsingContext') +const ScriptManager = require('../../bidi/scriptManager') +const { + ChannelValue, + LocalValue, + ReferenceValue, + RemoteReferenceType, +} = require('../../bidi/protocolValue') +const {ArgumentValue} = require('../../bidi/argumentValue') +const {EvaluateResultType} = require('../../bidi/evaluateResult') +const {ResultOwnership} = require('../../bidi/resultOwnership') +const {RealmType} = require('../../bidi/realmInfo') +const {WebDriverError} = require('../../lib/error') + +suite( + function (env) { + let driver + + beforeEach(async function () { + driver = await env + .builder() + .setFirefoxOptions(new firefox.Options().enableBidi()) + .build() + }) + + afterEach(async function () { + await driver.quit() + }) + + describe('Script Manager', function () { + 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, 3) + }) + + it('can call function to get iframe browsing context', async function () { + await driver.get(Pages.iframePage) + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + const result = await manager.callFunctionInBrowsingContext( + id, + '() => document.querySelector(\'iframe[id="iframe1"]\').contentWindow', + false + ) + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'window') + assert.notEqual(result.result.value, null) + assert.notEqual(result.result.value.context, 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'array') + assert.notEqual(result.result.value, null) + 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'string') + assert.notEqual(result.result.value, null) + 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'promise') + assert.equal(result.result.value, undefined) + }) + + 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + 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) + assert.notEqual(result.realmId, null) + assert.notEqual(result.result.handle, null) + assert.notEqual(result.result.value, null) + }) + + 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.notEqual(result.realmId, null) + + 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) + + // Make changes without sandbox + await manager.callFunctionInBrowsingContext( + id, + '() => { window.foo = 1; }', + true + ) + + // Check changes are not present in the sandbox + const resultNotInSandbox = await manager.callFunctionInBrowsingContext( + id, + '() => window.foo', + true, + null, + null, + null, + 'sandbox' + ) + + assert.equal(resultNotInSandbox.resultType, EvaluateResultType.SUCCESS) + assert.equal(resultNotInSandbox.result.type, 'undefined') + + // Make changes in the sandbox + + await manager.callFunctionInBrowsingContext( + id, + '() => { window.foo = 2; }', + true, + null, + null, + null, + 'sandbox' + ) + + // Check if the changes are present in the sandbox + + const resultInSandbox = await manager.callFunctionInBrowsingContext( + id, + '() => window.foo', + true, + null, + null, + null, + 'sandbox' + ) + + assert.equal(resultInSandbox.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(resultInSandbox.realmId, null) + + assert.equal(resultInSandbox.result.type, 'number') + assert.notEqual(resultInSandbox.result.value, null) + assert.equal(resultInSandbox.result.value, 2) + }) + + 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 firstTabRealmId = realms[0].realmId + const secondTabRealmId = realms[1].realmId + + await manager.callFunctionInRealm( + firstTabRealmId, + '() => { window.foo = 3; }', + true + ) + + await manager.callFunctionInRealm( + secondTabRealmId, + '() => { window.foo = 5; }', + true + ) + + const firstContextResult = await manager.callFunctionInRealm( + firstTabRealmId, + '() => window.foo', + true + ) + + assert.equal(firstContextResult.resultType, EvaluateResultType.SUCCESS) + assert.equal(firstContextResult.result.type, 'number') + assert.notEqual(firstContextResult.result.value, null) + assert.equal(firstContextResult.result.value, 3) + + const secondContextResult = await manager.callFunctionInRealm( + secondTabRealmId, + '() => window.foo', + true + ) + + assert.equal(secondContextResult.resultType, EvaluateResultType.SUCCESS) + assert.equal(secondContextResult.result.type, 'number') + assert.notEqual(secondContextResult.result.value, null) + assert.equal(secondContextResult.result.value, 5) + }) + + 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.notEqual(result.realmId, null) + assert.equal(result.result.type, 'number') + assert.notEqual(result.result.value, null) + 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.notEqual(result.realmId, null) + + 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.realmId, null) + assert.equal(result.result.type, 'object') + assert.notEqual(result.result.value, null) + 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) + + // Make changes without sandbox + await manager.evaluateFunctionInBrowsingContext( + id, + 'window.foo = 1', + true + ) + + // Check changes are not present in the sandbox + const resultNotInSandbox = + await manager.evaluateFunctionInBrowsingContext( + id, + 'window.foo', + true, + null, + 'sandbox' + ) + + assert.equal(resultNotInSandbox.resultType, EvaluateResultType.SUCCESS) + assert.equal(resultNotInSandbox.result.type, 'undefined') + + // Make changes in the sandbox + 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.notEqual(resultInSandbox.realmId, null) + + assert.equal(resultInSandbox.result.type, 'number') + assert.notEqual(resultInSandbox.result.value, null) + 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 firstTabRealmId = realms[0].realmId + const secondTabRealmId = realms[1].realmId + + await manager.evaluateFunctionInRealm( + firstTabRealmId, + 'window.foo = 3', + true + ) + + await manager.evaluateFunctionInRealm( + secondTabRealmId, + 'window.foo = 5', + true + ) + + const firstContextResult = await manager.evaluateFunctionInRealm( + firstTabRealmId, + 'window.foo', + true + ) + + assert.equal(firstContextResult.resultType, EvaluateResultType.SUCCESS) + assert.equal(firstContextResult.result.type, 'number') + assert.notEqual(firstContextResult.result.value, null) + assert.equal(firstContextResult.result.value, 3) + + const secondContextResult = await manager.evaluateFunctionInRealm( + secondTabRealmId, + 'window.foo', + true + ) + + assert.equal(secondContextResult.resultType, EvaluateResultType.SUCCESS) + assert.equal(secondContextResult.result.type, 'number') + assert.notEqual(secondContextResult.result.value, null) + assert.equal(secondContextResult.result.value, 5) + }) + + it('can disown handles', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + const evaluateResult = await manager.evaluateFunctionInBrowsingContext( + id, + '({a:1})', + false, + ResultOwnership.ROOT + ) + + assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(evaluateResult.realmId, null) + assert.notEqual(evaluateResult.result.handle, null) + + let argumentValues = [] + let valueMap = evaluateResult.result.value + + let value1 = new ArgumentValue(LocalValue.createObjectValue(valueMap)) + let value2 = new ArgumentValue( + new ReferenceValue( + RemoteReferenceType.HANDLE, + evaluateResult.result.handle + ) + ) + argumentValues.push(value1) + argumentValues.push(value2) + + await manager.callFunctionInBrowsingContext( + id, + 'arg => arg.a', + false, + argumentValues + ) + + assert.notEqual(evaluateResult.result.value, null) + + let handles = [evaluateResult.result.handle] + await manager.disownBrowsingContextScript(id, handles) + + await manager + .callFunctionInBrowsingContext( + id, + 'arg => arg.a', + false, + argumentValues + ) + .catch((error) => { + assert(error instanceof TypeError) + }) + }) + + it('can disown handles in realm', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + const evaluateResult = await manager.evaluateFunctionInBrowsingContext( + id, + '({a:1})', + false, + ResultOwnership.ROOT + ) + + assert.equal(evaluateResult.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(evaluateResult.realmId, null) + assert.notEqual(evaluateResult.result.handle, null) + + let argumentValues = [] + let valueMap = evaluateResult.result.value + + let value1 = new ArgumentValue(LocalValue.createObjectValue(valueMap)) + let value2 = new ArgumentValue( + new ReferenceValue( + RemoteReferenceType.HANDLE, + evaluateResult.result.handle + ) + ) + argumentValues.push(value1) + argumentValues.push(value2) + + await manager.callFunctionInBrowsingContext( + id, + 'arg => arg.a', + false, + argumentValues + ) + + assert.notEqual(evaluateResult.result.value, null) + + let handles = [evaluateResult.result.handle] + await manager.disownRealmScript(evaluateResult.realmId, handles) + + await manager + .callFunctionInBrowsingContext( + id, + 'arg => arg.a', + false, + argumentValues + ) + .catch((error) => { + assert(error instanceof TypeError) + }) + }) + + 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) + + const firstWindowRealm = realms[0] + assert.equal(firstWindowRealm.realmType, RealmType.WINDOW) + assert.notEqual(firstWindowRealm.realmId, null) + assert.equal(firstWindowRealm.browsingContext, firstWindow) + + const secondWindowRealm = realms[1] + assert.equal(secondWindowRealm.realmType, RealmType.WINDOW) + assert.notEqual(secondWindowRealm.realmId, null) + assert.equal(secondWindowRealm.browsingContext, secondWindow) + }) + + 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) + + const firstWindowRealm = realms[0] + assert.equal(firstWindowRealm.realmType, RealmType.WINDOW) + assert.notEqual(firstWindowRealm.realmId, null) + assert.equal(firstWindowRealm.browsingContext, firstWindow) + + const secondWindowRealm = realms[1] + assert.equal(secondWindowRealm.realmType, RealmType.WINDOW) + assert.notEqual(secondWindowRealm.realmId, null) + assert.equal(secondWindowRealm.browsingContext, secondWindow) + }) + + 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) + assert.notEqual(tabRealm.realmId, null) + assert.equal(tabRealm.browsingContext, tabId) + }) + + 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) + assert.notEqual(windowRealm.realmId, null) + assert.equal(windowRealm.browsingContext, windowId) + }) + + it('can add preload script', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + await manager.addPreloadScript("() => { window.foo='bar'; }") + + // Check that preload script didn't apply the changes to the current context + let result = await manager.evaluateFunctionInBrowsingContext( + id, + 'window.foo', + true + ) + assert.equal(result.result.type, 'undefined') + + await driver.switchTo().newWindow('window') + const new_window_id = await driver.getWindowHandle() + + // Check that preload script applied the changes to the window + result = await manager.evaluateFunctionInBrowsingContext( + new_window_id, + 'window.foo', + true + ) + + assert.equal(result.resultType, EvaluateResultType.SUCCESS) + assert.notEqual(result.realmId, null) + assert.equal(result.result.type, 'string') + assert.notEqual(result.result.value, null) + assert.equal(result.result.value, 'bar') + + const browsingContext = await BrowsingContext(driver, { + type: 'tab', + }) + + await browsingContext.navigate(Pages.logEntryAdded, 'complete') + + // Check that preload script was applied after navigation + result = await manager.evaluateFunctionInBrowsingContext( + new_window_id, + 'window.foo', + true + ) + + assert.equal(result.result.type, 'string') + assert.equal(result.result.value, 'bar') + }) + + it('can add same preload script twice', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + const script_1 = await manager.addPreloadScript('() => { return 42; }') + const script_2 = await manager.addPreloadScript('() => { return 42; }') + + assert.notEqual(script_1, script_2) + }) + + it('can access preload script properties', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + await manager.addPreloadScript( + '() => { window.preloadScriptFunction = () => window.baz = 42; }' + ) + + await driver.switchTo().newWindow('tab') + const new_tab_id = await driver.getWindowHandle() + await driver.get(Pages.scriptTestAccessProperty) + + const result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.baz', + true + ) + + assert.equal(result.result.type, 'number') + assert.equal(result.result.value, 42) + }) + + it('can add preload script to sandbox', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + await manager.addPreloadScript('() => { window.foo = 1; }') + await manager.addPreloadScript( + '() => { window.bar = 2; }', + [], + 'sandbox' + ) + + await driver.switchTo().newWindow('tab') + const new_tab_id = await driver.getWindowHandle() + + let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.foo', + true, + null, + 'sandbox' + ) + + assert.equal(result_in_sandbox.result.type, 'undefined') + + let result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.bar', + true + ) + + assert.equal(result.result.type, 'undefined') + + result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( + new_tab_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 properties set by preload script', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + await manager.addPreloadScript('() => { window.foo = 42; }') + await manager.addPreloadScript( + '() => { window.foo = 50; }', + [], + 'sandbox_1' + ) + + await driver.switchTo().newWindow('tab') + const new_tab_id = await driver.getWindowHandle() + await driver.get(Pages.scriptTestRemoveProperty) + + let result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.foo', + true + ) + assert.equal(result.result.type, 'undefined') + + result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.foo', + true, + null, + 'sandbox_1' + ) + assert.equal(result.result.type, 'number') + assert.equal(result.result.value, 50) + }) + + it('can remove preload script', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + let script = await manager.addPreloadScript( + "() => { window.foo='bar'; }" + ) + + await driver.switchTo().newWindow('tab') + const tab_1_id = await driver.getWindowHandle() + + let result = await manager.evaluateFunctionInBrowsingContext( + tab_1_id, + 'window.foo', + true + ) + + assert.equal(result.result.type, 'string') + assert.equal(result.result.value, 'bar') + + await manager.removePreloadScript(script) + + await driver.switchTo().newWindow('tab') + const tab_2_id = await driver.getWindowHandle() + + // Check that changes from preload script were not applied after script was removed + result = await manager.evaluateFunctionInBrowsingContext( + tab_2_id, + 'window.foo', + true + ) + + assert.equal(result.result.type, 'undefined') + }) + + it('cannot remove same preload script twice', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + let script = await manager.addPreloadScript( + "() => { window.foo='bar'; }" + ) + + await manager.removePreloadScript(script) + + await manager.removePreloadScript(script).catch((error) => { + assert(error instanceof WebDriverError) + }) + }) + + it('can remove one of preload script', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + let script_1 = await manager.addPreloadScript( + "() => { window.bar='foo'; }" + ) + + let script_2 = await manager.addPreloadScript( + "() => { window.baz='bar'; }" + ) + + await manager.removePreloadScript(script_1) + + await driver.switchTo().newWindow('tab') + const new_tab_id = await driver.getWindowHandle() + + // Check that the first script didn't run + let result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.bar', + true + ) + + assert.equal(result.result.type, 'undefined') + + // Check that the second script still applied the changes to the window + result = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.baz', + true + ) + + assert.equal(result.result.type, 'string') + assert.equal(result.result.value, 'bar') + + // Clean up the second script + await manager.removePreloadScript(script_2) + }) + + it('can remove one of preload script from sandbox', async function () { + const id = await driver.getWindowHandle() + const manager = await ScriptManager(id, driver) + + let script_1 = await manager.addPreloadScript( + '() => { window.foo = 1; }' + ) + + let script_2 = await manager.addPreloadScript( + '() => { window.bar = 2; }', + [], + 'sandbox' + ) + + // Remove first preload script + await manager.removePreloadScript(script_1) + + // Remove second preload script + await manager.removePreloadScript(script_2) + + await driver.switchTo().newWindow('tab') + const new_tab_id = await driver.getWindowHandle() + + // Make sure that changes from first preload script were not applied + let result_in_window = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.foo', + true + ) + + assert.equal(result_in_window.result.type, 'undefined') + + // Make sure that changes from second preload script were not applied + let result_in_sandbox = await manager.evaluateFunctionInBrowsingContext( + new_tab_id, + 'window.bar', + true, + null, + 'sandbox' + ) + + assert.equal(result_in_sandbox.result.type, 'undefined') + }) + + 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(Pages.blankPage, 'complete') + + assert.notEqual(realmInfo, null) + assert.notEqual(realmInfo.realmId, null) + assert.equal(realmInfo.realmType, RealmType.WINDOW) + }) + }) + }, + {browsers: [Browser.FIREFOX]} +)