Skip to content

Commit 683aba6

Browse files
authored
Merge branch 'trunk' into py-bidi-proxy
2 parents 51f0eb1 + f787770 commit 683aba6

File tree

8 files changed

+456
-23
lines changed

8 files changed

+456
-23
lines changed

.github/workflows/ci-java.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
java-version: 17
2424
run: |
2525
fsutil 8dot3name set 0
26-
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest `
26+
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest `
2727
//java/test/org/openqa/selenium/federatedcredentialmanagement:FederatedCredentialManagementTest `
2828
//java/test/org/openqa/selenium/firefox:FirefoxDriverBuilderTest `
2929
//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest `
@@ -47,7 +47,7 @@ jobs:
4747
# https://github.com/bazelbuild/rules_jvm_external/issues/1046
4848
java-version: 17
4949
run: |
50-
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote \
50+
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote \
5151
//java/test/org/openqa/selenium/federatedcredentialmanagement:FederatedCredentialManagementTest \
5252
//java/test/org/openqa/selenium/firefox:FirefoxDriverBuilderTest \
5353
//java/test/org/openqa/selenium/grid/router:RemoteWebDriverDownloadTest \
@@ -71,4 +71,4 @@ jobs:
7171
# https://github.com/bazelbuild/rules_jvm_external/issues/1046
7272
java-version: 17
7373
run: |
74-
bazel test --flaky_test_attempts 3 //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote
74+
bazel test --flaky_test_attempts 3 --pin_browsers=true //java/test/org/openqa/selenium/chrome:ChromeDriverFunctionalTest-remote

.github/workflows/ci-python.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ jobs:
8989
os: ${{ matrix.os }}
9090
cache-key: py-browser-${{ matrix.browser }}
9191
run: |
92-
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:common-${{ matrix.browser }}-bidi
93-
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:test-${{ matrix.browser }}
92+
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:common-${{ matrix.browser }}-bidi
93+
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:test-${{ matrix.browser }}
9494
9595
safari-tests:
9696
name: Browser Tests
@@ -108,4 +108,4 @@ jobs:
108108
os: ${{ matrix.os }}
109109
cache-key: py-browser-${{ matrix.browser }}
110110
run: |
111-
bazel test --local_test_jobs 1 --flaky_test_attempts 3 //py:test-${{ matrix.browser }}
111+
bazel test --local_test_jobs 1 --flaky_test_attempts 3 --pin_browsers=true //py:test-${{ matrix.browser }}

.github/workflows/ci-ruby.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
--local_test_jobs 1
8585
--test_size_filters large
8686
--test_tag_filters ${{ matrix.browser }}
87-
${{ matrix.os != 'windows' && '--pin_browsers' || '' }}
87+
--pin_browsers
8888
//rb/spec/...
8989
9090
integration-tests-remote:
@@ -111,5 +111,5 @@ jobs:
111111
--local_test_jobs 1
112112
--test_size_filters large
113113
--test_tag_filters ${{ matrix.browser }}-remote
114-
${{ matrix.os != 'windows' && '--pin_browsers' || '' }}
114+
--pin_browsers
115115
//rb/spec/...

common/repositories.bzl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ js_library(
5050

5151
http_archive(
5252
name = "linux_beta_firefox",
53-
url = "https://ftp.mozilla.org/pub/firefox/releases/141.0b3/linux-x86_64/en-US/firefox-141.0b3.tar.xz",
54-
sha256 = "9f7cc8fc0ee1ae566a6ff54721428ef733d27baf8edae5bb7b8b9117616e48da",
53+
url = "https://ftp.mozilla.org/pub/firefox/releases/141.0b4/linux-x86_64/en-US/firefox-141.0b4.tar.xz",
54+
sha256 = "04e66e3e8a7512d2f45b69fe9385c6820182e7b8addfaac218ee10a108a08e6b",
5555
build_file_content = """
5656
load("@aspect_rules_js//js:defs.bzl", "js_library")
5757
package(default_visibility = ["//visibility:public"])
@@ -72,8 +72,8 @@ js_library(
7272

7373
dmg_archive(
7474
name = "mac_beta_firefox",
75-
url = "https://ftp.mozilla.org/pub/firefox/releases/141.0b3/mac/en-US/Firefox%20141.0b3.dmg",
76-
sha256 = "47dc6a456bc80baa784381e94f4dc4f2f7ddfdf94b0af0bb20d9678f16d28898",
75+
url = "https://ftp.mozilla.org/pub/firefox/releases/141.0b4/mac/en-US/Firefox%20141.0b4.dmg",
76+
sha256 = "edcd3074f81a3e318aa672db0ec48f2c57c9eebbe9275e22fd64a42c9eb8d29b",
7777
build_file_content = """
7878
load("@aspect_rules_js//js:defs.bzl", "js_library")
7979
package(default_visibility = ["//visibility:public"])
@@ -199,8 +199,8 @@ js_library(
199199

200200
http_archive(
201201
name = "linux_chrome",
202-
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.49/linux64/chrome-linux64.zip",
203-
sha256 = "8751e9a4a0ca7c8127acb06c4fe0c438d091c0fb1c3712dcd4ea277773177304",
202+
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.92/linux64/chrome-linux64.zip",
203+
sha256 = "c8bce5bd95f82521ee7c83d9f020104ca0a77ff76cad6d45dbf8e244910f46d1",
204204
build_file_content = """
205205
load("@aspect_rules_js//js:defs.bzl", "js_library")
206206
package(default_visibility = ["//visibility:public"])
@@ -220,8 +220,8 @@ js_library(
220220
)
221221
http_archive(
222222
name = "mac_chrome",
223-
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.49/mac-x64/chrome-mac-x64.zip",
224-
sha256 = "98e4f2e97a31ca7104f72ca1fbe506b0070dd181f0bccc1b4af90ff950ceaa57",
223+
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.92/mac-x64/chrome-mac-x64.zip",
224+
sha256 = "889784221d05ba0ff8fd4ca8befc6696b3dd4d2e630f7825c3fec8cedb6a8021",
225225
strip_prefix = "chrome-mac-x64",
226226
patch_cmds = [
227227
"mv 'Google Chrome for Testing.app' Chrome.app",
@@ -241,8 +241,8 @@ js_library(
241241
)
242242
http_archive(
243243
name = "linux_chromedriver",
244-
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.49/linux64/chromedriver-linux64.zip",
245-
sha256 = "0ef562acf7a87733a77cf51f52e3841cf7fb63c17d618b6ccb45a9a53ca89017",
244+
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.92/linux64/chromedriver-linux64.zip",
245+
sha256 = "4bb3830e85ee50fceed2634c1552842350a267d8d822e3da07cb053f840a8261",
246246
strip_prefix = "chromedriver-linux64",
247247
build_file_content = """
248248
load("@aspect_rules_js//js:defs.bzl", "js_library")
@@ -259,8 +259,8 @@ js_library(
259259

260260
http_archive(
261261
name = "mac_chromedriver",
262-
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.49/mac-x64/chromedriver-mac-x64.zip",
263-
sha256 = "bff1fc6075912698a1699a8d0979da3fdc576775a3fe78e6ae68338459c8882f",
262+
url = "https://storage.googleapis.com/chrome-for-testing-public/138.0.7204.92/mac-x64/chromedriver-mac-x64.zip",
263+
sha256 = "5d1a8aed0a7ac955680a1a33964f1d48b2d09241752c79914de64012bd5e6ddb",
264264
strip_prefix = "chromedriver-mac-x64",
265265
build_file_content = """
266266
load("@aspect_rules_js//js:defs.bzl", "js_library")

java/test/org/openqa/selenium/federatedcredentialmanagement/FederatedCredentialManagementTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.List;
3030
import org.junit.jupiter.api.AfterEach;
3131
import org.junit.jupiter.api.BeforeEach;
32+
import org.junit.jupiter.api.Disabled;
3233
import org.junit.jupiter.api.Test;
3334
import org.openqa.selenium.By;
3435
import org.openqa.selenium.NoAlertPresentException;
@@ -40,6 +41,7 @@
4041
import org.openqa.selenium.environment.webserver.AppServer;
4142
import org.openqa.selenium.support.ui.WebDriverWait;
4243

44+
@Disabled("https://issues.chromium.org/u/0/issues/425801332")
4345
class FederatedCredentialManagementTest {
4446

4547
private HasFederatedCredentialManagement fedcmDriver;

py/selenium/webdriver/common/bidi/script.py

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18+
import datetime
19+
import math
1820
from dataclasses import dataclass
1921
from typing import Any, Optional
2022

23+
from selenium.common.exceptions import WebDriverException
2124
from selenium.webdriver.common.bidi.common import command_builder
2225

2326
from .log import LogEntryAdded
@@ -238,12 +241,15 @@ class Script:
238241
"realm_destroyed": "script.realmDestroyed",
239242
}
240243

241-
def __init__(self, conn):
244+
def __init__(self, conn, driver=None):
242245
self.conn = conn
246+
self.driver = driver
243247
self.log_entry_subscribed = False
244248
self.subscriptions = {}
245249
self.callbacks = {}
246250

251+
# High-level APIs for SCRIPT module
252+
247253
def add_console_message_handler(self, handler):
248254
self._subscribe_to_log_entries()
249255
return self.conn.add_callback(LogEntryAdded, self._handle_log_entry("console", handler))
@@ -258,6 +264,122 @@ def remove_console_message_handler(self, id):
258264

259265
remove_javascript_error_handler = remove_console_message_handler
260266

267+
def pin(self, script: str) -> str:
268+
"""Pins a script to the current browsing context.
269+
270+
Parameters:
271+
-----------
272+
script: The script to pin.
273+
274+
Returns:
275+
-------
276+
str: The ID of the pinned script.
277+
"""
278+
return self._add_preload_script(script)
279+
280+
def unpin(self, script_id: str) -> None:
281+
"""Unpins a script from the current browsing context.
282+
283+
Parameters:
284+
-----------
285+
script_id: The ID of the pinned script to unpin.
286+
"""
287+
self._remove_preload_script(script_id)
288+
289+
def execute(self, script: str, *args) -> dict:
290+
"""Executes a script in the current browsing context.
291+
292+
Parameters:
293+
-----------
294+
script: The script function to execute.
295+
*args: Arguments to pass to the script function.
296+
297+
Returns:
298+
-------
299+
dict: The result value from the script execution.
300+
301+
Raises:
302+
------
303+
WebDriverException: If the script execution fails.
304+
"""
305+
306+
if self.driver is None:
307+
raise WebDriverException("Driver reference is required for script execution")
308+
browsing_context_id = self.driver.current_window_handle
309+
310+
# Convert arguments to the format expected by BiDi call_function (LocalValue Type)
311+
arguments = []
312+
for arg in args:
313+
arguments.append(self.__convert_to_local_value(arg))
314+
315+
target = {"context": browsing_context_id}
316+
317+
result = self._call_function(
318+
function_declaration=script, await_promise=True, target=target, arguments=arguments if arguments else None
319+
)
320+
321+
if result.type == "success":
322+
return result.result
323+
else:
324+
error_message = "Error while executing script"
325+
if result.exception_details:
326+
if "text" in result.exception_details:
327+
error_message += f": {result.exception_details['text']}"
328+
elif "message" in result.exception_details:
329+
error_message += f": {result.exception_details['message']}"
330+
331+
raise WebDriverException(error_message)
332+
333+
def __convert_to_local_value(self, value) -> dict:
334+
"""
335+
Converts a Python value to BiDi LocalValue format.
336+
"""
337+
if value is None:
338+
return {"type": "null"}
339+
elif isinstance(value, bool):
340+
return {"type": "boolean", "value": value}
341+
elif isinstance(value, (int, float)):
342+
if isinstance(value, float):
343+
if math.isnan(value):
344+
return {"type": "number", "value": "NaN"}
345+
elif math.isinf(value):
346+
if value > 0:
347+
return {"type": "number", "value": "Infinity"}
348+
else:
349+
return {"type": "number", "value": "-Infinity"}
350+
elif value == 0.0 and math.copysign(1.0, value) < 0:
351+
return {"type": "number", "value": "-0"}
352+
353+
JS_MAX_SAFE_INTEGER = 9007199254740991
354+
if isinstance(value, int) and (value > JS_MAX_SAFE_INTEGER or value < -JS_MAX_SAFE_INTEGER):
355+
return {"type": "bigint", "value": str(value)}
356+
357+
return {"type": "number", "value": value}
358+
359+
elif isinstance(value, str):
360+
return {"type": "string", "value": value}
361+
elif isinstance(value, datetime.datetime):
362+
# Convert Python datetime to JavaScript Date (ISO 8601 format)
363+
return {"type": "date", "value": value.isoformat() + "Z" if value.tzinfo is None else value.isoformat()}
364+
elif isinstance(value, datetime.date):
365+
# Convert Python date to JavaScript Date
366+
dt = datetime.datetime.combine(value, datetime.time.min).replace(tzinfo=datetime.timezone.utc)
367+
return {"type": "date", "value": dt.isoformat()}
368+
elif isinstance(value, set):
369+
return {"type": "set", "value": [self.__convert_to_local_value(item) for item in value]}
370+
elif isinstance(value, (list, tuple)):
371+
return {"type": "array", "value": [self.__convert_to_local_value(item) for item in value]}
372+
elif isinstance(value, dict):
373+
return {
374+
"type": "object",
375+
"value": [
376+
[self.__convert_to_local_value(k), self.__convert_to_local_value(v)] for k, v in value.items()
377+
],
378+
}
379+
else:
380+
# For other types, convert to string
381+
return {"type": "string", "value": str(value)}
382+
261383
# low-level APIs for script module
262384
def _add_preload_script(
263385
self,

py/selenium/webdriver/remote/webdriver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ def script(self):
12401240
self._start_bidi()
12411241

12421242
if not self._script:
1243-
self._script = Script(self._websocket_connection)
1243+
self._script = Script(self._websocket_connection, self)
12441244

12451245
return self._script
12461246

0 commit comments

Comments
 (0)