From 8b5f33bafe548bed020cf49184a59d1792f10d95 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Mon, 1 Apr 2024 16:24:11 +0530 Subject: [PATCH 1/3] [bidi][java] Add browsing context create parameters --- .../bidi/browsingcontext/BrowsingContext.java | 26 +++++++--- .../CreateContextParameters.java | 51 +++++++++++++++++++ .../browsingcontext/BrowsingContextTest.java | 30 ++++++++++- 3 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 java/src/org/openqa/selenium/bidi/browsingcontext/CreateContextParameters.java diff --git a/java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContext.java b/java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContext.java index 79ff714d5ce1d..56cabb758f266 100644 --- a/java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContext.java +++ b/java/src/org/openqa/selenium/bidi/browsingcontext/BrowsingContext.java @@ -105,6 +105,11 @@ public BrowsingContext(WebDriver driver, WindowType type) { this.id = this.create(type); } + /* + * @deprecated + * Use {@link #BrowsingContext(WebDriver, CreateParameters)} instead. + */ + @Deprecated public BrowsingContext(WebDriver driver, WindowType type, String referenceContextId) { Require.nonNull("WebDriver", driver); Require.nonNull("Reference browsing context id", referenceContextId); @@ -117,7 +122,19 @@ public BrowsingContext(WebDriver driver, WindowType type, String referenceContex this.driver = driver; this.bidi = ((HasBiDi) driver).getBiDi(); - this.id = this.create(type, referenceContextId); + this.id = this.create(new CreateContextParameters(type).referenceContext(referenceContextId)); + } + + public BrowsingContext(WebDriver driver, CreateContextParameters parameters) { + Require.nonNull("WebDriver", driver); + + if (!(driver instanceof HasBiDi)) { + throw new IllegalArgumentException("WebDriver instance must support BiDi protocol"); + } + + this.driver = driver; + this.bidi = ((HasBiDi) driver).getBiDi(); + this.id = this.create(parameters); } public String getId() { @@ -130,12 +147,9 @@ private String create(WindowType type) { "browsingContext.create", Map.of("type", type.toString()), browsingContextIdMapper)); } - private String create(WindowType type, String referenceContext) { + private String create(CreateContextParameters parameters) { return this.bidi.send( - new Command<>( - "browsingContext.create", - Map.of("type", type.toString(), "referenceContext", referenceContext), - browsingContextIdMapper)); + new Command<>("browsingContext.create", parameters.toMap(), browsingContextIdMapper)); } public NavigationResult navigate(String url) { diff --git a/java/src/org/openqa/selenium/bidi/browsingcontext/CreateContextParameters.java b/java/src/org/openqa/selenium/bidi/browsingcontext/CreateContextParameters.java new file mode 100644 index 0000000000000..198f136944770 --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/browsingcontext/CreateContextParameters.java @@ -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. + +package org.openqa.selenium.bidi.browsingcontext; + +import java.util.HashMap; +import java.util.Map; +import org.openqa.selenium.WindowType; + +public class CreateContextParameters { + private final Map map = new HashMap<>(); + private final WindowType windowType; + + public CreateContextParameters(WindowType type) { + this.windowType = type; + } + + public CreateContextParameters referenceContext(String id) { + map.put("referenceContext", id); + return this; + } + + public CreateContextParameters background(boolean background) { + map.put("background", background); + return this; + } + + public CreateContextParameters userContext(String userContext) { + map.put("userContext", userContext); + return this; + } + + public Map toMap() { + map.put("type", windowType.toString()); + return map; + } +} diff --git a/java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextTest.java b/java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextTest.java index d4a2295ac81dc..53d681d016333 100644 --- a/java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextTest.java +++ b/java/test/org/openqa/selenium/bidi/browsingcontext/BrowsingContextTest.java @@ -39,6 +39,7 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.WindowType; import org.openqa.selenium.bidi.BiDiException; +import org.openqa.selenium.bidi.module.Browser; import org.openqa.selenium.environment.webserver.AppServer; import org.openqa.selenium.environment.webserver.NettyAppServer; import org.openqa.selenium.environment.webserver.Page; @@ -81,7 +82,10 @@ void canCreateAWindow() { @NotYetImplemented(EDGE) void canCreateAWindowWithAReferenceContext() { BrowsingContext browsingContext = - new BrowsingContext(driver, WindowType.WINDOW, driver.getWindowHandle()); + new BrowsingContext( + driver, + new CreateContextParameters(WindowType.WINDOW) + .referenceContext(driver.getWindowHandle())); assertThat(browsingContext.getId()).isNotEmpty(); } @@ -100,10 +104,32 @@ void canCreateATab() { @NotYetImplemented(EDGE) void canCreateATabWithAReferenceContext() { BrowsingContext browsingContext = - new BrowsingContext(driver, WindowType.TAB, driver.getWindowHandle()); + new BrowsingContext( + driver, + new CreateContextParameters(WindowType.TAB).referenceContext(driver.getWindowHandle())); assertThat(browsingContext.getId()).isNotEmpty(); } + @Test + @NotYetImplemented(SAFARI) + @NotYetImplemented(IE) + @NotYetImplemented(CHROME) + @NotYetImplemented(EDGE) + void canCreateAContextWithAllParameters() { + Browser browser = new Browser(driver); + String userContextId = browser.createUserContext(); + + CreateContextParameters parameters = new CreateContextParameters(WindowType.WINDOW); + parameters + .referenceContext(driver.getWindowHandle()) + .userContext(userContextId) + .background(true); + + BrowsingContext browsingContext = new BrowsingContext(driver, parameters); + assertThat(browsingContext.getId()).isNotEmpty(); + assertThat(browsingContext.getId()).isNotEqualTo(driver.getWindowHandle()); + } + @Test @NotYetImplemented(SAFARI) @NotYetImplemented(IE) From fbfc6644d8614e12e5df7839544a036dc7a0179b Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Tue, 2 Apr 2024 15:52:44 +0530 Subject: [PATCH 2/3] [bidi][js] Add create parameters and update the init method for it. Remove referenceContext param. --- .../bidi/browsingContext.js | 47 ++++++++++++----- .../bidi/createContextParameters.js | 50 +++++++++++++++++++ .../test/bidi/browsingcontext_test.js | 20 +++++++- 3 files changed, 103 insertions(+), 14 deletions(-) create mode 100644 javascript/node/selenium-webdriver/bidi/createContextParameters.js diff --git a/javascript/node/selenium-webdriver/bidi/browsingContext.js b/javascript/node/selenium-webdriver/bidi/browsingContext.js index eb9bb88160146..63c3ac38348ff 100644 --- a/javascript/node/selenium-webdriver/bidi/browsingContext.js +++ b/javascript/node/selenium-webdriver/bidi/browsingContext.js @@ -20,6 +20,7 @@ const { BrowsingContextInfo } = require('./browsingContextTypes') const { SerializationOptions, ReferenceValue, RemoteValue } = require('./protocolValue') const { WebElement } = require('../lib/webdriver') const { CaptureScreenshotParameters } = require('./captureScreenshotParameters') +const { CreateContextParameters } = require('./createContextParameters') class Locator { static Type = Object.freeze({ @@ -79,11 +80,19 @@ class BrowsingContext { return this._id } - async init({ browsingContextId, type, referenceContext }) { + async init({ browsingContextId = undefined, type = undefined, createParameters = undefined }) { if (!(await this._driver.getCapabilities()).get('webSocketUrl')) { throw Error('WebDriver instance must support BiDi protocol') } + if (browsingContextId === undefined && type === undefined && createParameters === undefined) { + throw Error('Either BrowsingContextId or Type or CreateParameters must be provided') + } + + if (type === undefined && createParameters !== undefined) { + throw Error('Type must be provided with CreateParameters') + } + if (type !== undefined && !['window', 'tab'].includes(type)) { throw Error(`Valid types are 'window' & 'tab'. Received: ${type}`) } @@ -91,22 +100,33 @@ class BrowsingContext { this.bidi = await this._driver.getBidi() this._id = browsingContextId === undefined - ? (await this.create(type, referenceContext))['result']['context'] + ? (await this.create(type, createParameters))['result']['context'] : browsingContextId } /** - * Creates a browsing context for the given type and referenceContext + * Creates a browsing context for the given type with the given parameters */ - async create(type, referenceContext) { + async create(type, createParameters = undefined) { + if (createParameters !== undefined && (!createParameters) instanceof CreateContextParameters) { + throw Error(`Pass in the instance of CreateContextParameters. Received: ${createParameters}`) + } + + let parameters = new Map() + parameters.set('type', type) + + if (createParameters !== undefined) { + createParameters.asMap().forEach((value, key) => { + parameters.set(key, value) + }) + } + const params = { method: 'browsingContext.create', - params: { - type: type, - referenceContext: referenceContext, - }, + params: Object.fromEntries(parameters), } - return await this.bidi.send(params) + const res = await this.bidi.send(params) + return res } /** @@ -484,12 +504,15 @@ class PrintResult { * @param driver * @param browsingContextId The browsing context of current window/tab * @param type "window" or "tab" - * @param referenceContext To get a browsing context for this reference if passed + * @param createParameters The parameters for creating a new browsing context * @returns {Promise} */ -async function getBrowsingContextInstance(driver, { browsingContextId, type, referenceContext }) { +async function getBrowsingContextInstance( + driver, + { browsingContextId = undefined, type = undefined, createParameters = undefined }, +) { let instance = new BrowsingContext(driver) - await instance.init({ browsingContextId, type, referenceContext }) + await instance.init({ browsingContextId, type, createParameters }) return instance } diff --git a/javascript/node/selenium-webdriver/bidi/createContextParameters.js b/javascript/node/selenium-webdriver/bidi/createContextParameters.js new file mode 100644 index 0000000000000..9796a9829803b --- /dev/null +++ b/javascript/node/selenium-webdriver/bidi/createContextParameters.js @@ -0,0 +1,50 @@ +// 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. + +class CreateContextParameters { + #map = new Map() + + referenceContext(id) { + if (typeof id !== 'string') { + throw new Error(`ReferenceContext must be string. Received:'${id}'`) + } + this.#map.set('referenceContext', id) + return this + } + + background(background) { + if (typeof background !== 'boolean') { + throw new Error(`Background must be boolean. Received:'${background}'`) + } + this.#map.set('background', background) + return this + } + + userContext(userContext) { + if (typeof userContext !== 'string') { + throw new Error(`UserContext must be string. Received:'${userContext}'`) + } + this.#map.set('userContext', userContext) + return this + } + + asMap() { + return this.#map + } +} + +module.exports = { CreateContextParameters } diff --git a/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js index 1c7094accc2cb..d4b77a84e184a 100644 --- a/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js +++ b/javascript/node/selenium-webdriver/test/bidi/browsingcontext_test.js @@ -25,6 +25,8 @@ const BrowsingContext = require('../../bidi/browsingContext') const until = require('../../lib/until') const { Origin, CaptureScreenshotParameters } = require('../../bidi/captureScreenshotParameters') const { BoxClipRectangle, ElementClipRectangle } = require('../../bidi/clipRectangle') +const { CreateContextParameters } = require('../../bidi/createContextParameters') +const BrowserBiDi = require('../../bidi/browser') suite( function (env) { @@ -62,11 +64,25 @@ suite( it('can create a window with a reference context', async function () { const browsingContext = await BrowsingContext(driver, { type: 'window', - referenceContext: await driver.getWindowHandle(), + createParameters: new CreateContextParameters().referenceContext(await driver.getWindowHandle()), }) assert.notEqual(browsingContext.id, null) }) + it('can create a tab with all parameters', async function () { + const browser = await BrowserBiDi(driver) + const userContext = await browser.createUserContext() + const browsingContext = await BrowsingContext(driver, { + type: 'window', + createParameters: new CreateContextParameters() + .referenceContext(await driver.getWindowHandle()) + .background(true) + .userContext(userContext), + }) + assert.notEqual(browsingContext.id, null) + assert.notEqual(browsingContext.id, await driver.getWindowHandle()) + }) + it('can create a tab', async function () { const browsingContext = await BrowsingContext(driver, { type: 'tab', @@ -77,7 +93,7 @@ suite( it('can create a tab with a reference context', async function () { const browsingContext = await BrowsingContext(driver, { type: 'tab', - referenceContext: await driver.getWindowHandle(), + referenceContext: new CreateContextParameters().referenceContext(await driver.getWindowHandle()), }) assert.notEqual(browsingContext.id, null) }) From 8ffee84bbe5b8b863c676d5aa9c9e82a533806c7 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Wed, 3 Apr 2024 10:15:13 +0530 Subject: [PATCH 3/3] [js] Add JS doc comment --- .../bidi/createContextParameters.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/javascript/node/selenium-webdriver/bidi/createContextParameters.js b/javascript/node/selenium-webdriver/bidi/createContextParameters.js index 9796a9829803b..bb69e1d0b0866 100644 --- a/javascript/node/selenium-webdriver/bidi/createContextParameters.js +++ b/javascript/node/selenium-webdriver/bidi/createContextParameters.js @@ -15,9 +15,19 @@ // specific language governing permissions and limitations // under the License. +/** + * Represents a set of parameters for creating a context. + * Described in https://w3c.github.io/webdriver-bidi/#command-browsingContext-create. + */ class CreateContextParameters { #map = new Map() + /** + * Sets the reference context. + * @param {string} id - The ID of the reference context. + * @returns {CreateContextParameters} - The updated instance of CreateContextParameters for chaining. + * @throws {Error} - If the provided ID is not a string. + */ referenceContext(id) { if (typeof id !== 'string') { throw new Error(`ReferenceContext must be string. Received:'${id}'`) @@ -26,6 +36,13 @@ class CreateContextParameters { return this } + /** + * Sets the background parameter. + * + * @param {boolean} background - The background value to set. + * @returns {CreateContextParameters} - The updated instance of CreateContextParameters for chaining. + * @throws {Error} - If the background parameter is not a boolean. + */ background(background) { if (typeof background !== 'boolean') { throw new Error(`Background must be boolean. Received:'${background}'`) @@ -34,6 +51,12 @@ class CreateContextParameters { return this } + /** + * Sets the user context. + * @param {string} userContext - The user context to set. + * @returns {CreateContextParameters} - The updated instance of CreateContextParameters for chaining. + * @throws {Error} - If the userContext parameter is not a string. + */ userContext(userContext) { if (typeof userContext !== 'string') { throw new Error(`UserContext must be string. Received:'${userContext}'`)