Skip to content

Commit 840ba04

Browse files
committed
[WebDriver] Selenium 4.34 tests teardown error due to reconnection errors on test failure
https://bugs.webkit.org/show_bug.cgi?id=296255 Reviewed by BJ Burg. Includes the fix upstreamed in SeleniumHQ/selenium#16271 This reduces the amount of MaxRetryErrors from 61 to 4, which now are related to ungardened tests. * WebDriverTests/imported/selenium/importer.json: Updated hash * WebDriverTests/imported/selenium/: Updated the selenium copy, with the usual skip of Chrome, Edge, and Firefox related code. Canonical link: https://commits.webkit.org/300552@main
1 parent 1d49e82 commit 840ba04

27 files changed

+2800
-247
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Page containing an image encoded as a Data URL</title>
6+
</head>
7+
<body>
8+
<img src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" alt="star" id="data-url-image">
9+
</body>
10+
</html>

WebDriverTests/imported/selenium/importer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"repository": "https://github.com/SeleniumHQ/selenium.git",
3-
"revision": "99c7cbf0427fdd41ee33a3049a22ce839580eabd",
3+
"revision": "01548e0a94254a8bd63a10dc7aa8dbf100f90869",
44
"paths_to_import": [
55
"common",
66
"py/conftest.py",

WebDriverTests/imported/selenium/py/conftest.py

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
# under the License.
1717

1818
import os
19-
import platform
19+
import sys
2020
from dataclasses import dataclass
2121
from pathlib import Path
2222

2323
import pytest
2424

2525
from selenium import webdriver
26+
from selenium.common.exceptions import WebDriverException
2627
from selenium.webdriver.remote.server import Server
2728
from test.selenium.webdriver.common.network import get_lan_ip
2829
from test.selenium.webdriver.common.webserver import SimpleWebServer
@@ -101,7 +102,6 @@ def pytest_generate_tests(metafunc):
101102
metafunc.parametrize("driver", metafunc.config.option.drivers, indirect=True)
102103

103104

104-
driver_instance = None
105105
selenium_driver = None
106106

107107

@@ -184,7 +184,14 @@ def driver_class(self, cls_name):
184184

185185
@property
186186
def exe_platform(self):
187-
return platform.system()
187+
if sys.platform == "win32":
188+
return "Windows"
189+
elif sys.platform == "darwin":
190+
return "Darwin"
191+
elif sys.platform == "linux":
192+
return "Linux"
193+
else:
194+
return sys.platform.title()
188195

189196
@property
190197
def browser_path(self):
@@ -271,7 +278,8 @@ def service(self):
271278

272279
@property
273280
def driver(self):
274-
self._driver = self._initialize_driver()
281+
if self._driver is None:
282+
self._driver = self._initialize_driver()
275283
return self._driver
276284

277285
@property
@@ -292,21 +300,15 @@ def _initialize_driver(self):
292300
kwargs["service"] = self.service
293301
return getattr(webdriver, self.driver_class)(**kwargs)
294302

295-
@property
296303
def stop_driver(self):
297-
def fin():
298-
global driver_instance
299-
if self._driver is not None:
300-
self._driver.quit()
301-
self._driver = None
302-
driver_instance = None
303-
304-
return fin
304+
driver_to_stop = self._driver
305+
self._driver = None
306+
if driver_to_stop is not None:
307+
driver_to_stop.quit()
305308

306309

307310
@pytest.fixture(scope="function")
308311
def driver(request):
309-
global driver_instance
310312
global selenium_driver
311313
driver_class = getattr(request, "param", "Chrome").lower()
312314

@@ -340,38 +342,43 @@ def driver(request):
340342

341343
request.addfinalizer(selenium_driver.stop_driver)
342344

343-
if driver_instance is None:
344-
driver_instance = selenium_driver.driver
345-
346-
yield driver_instance
347345
# Close the browser after BiDi tests. Those make event subscriptions
348346
# and doesn't seems to be stable enough, causing the flakiness of the
349347
# subsequent tests.
350348
# Remove this when BiDi implementation and API is stable.
351-
if selenium_driver.bidi:
349+
if selenium_driver is not None and selenium_driver.bidi:
352350
request.addfinalizer(selenium_driver.stop_driver)
353351

352+
yield selenium_driver.driver
353+
354354
if request.node.get_closest_marker("no_driver_after_test"):
355-
driver_instance = None
355+
if selenium_driver is not None:
356+
try:
357+
selenium_driver.stop_driver()
358+
except WebDriverException:
359+
pass
360+
except Exception:
361+
raise
362+
selenium_driver = None
356363

357364

358365
@pytest.fixture(scope="session", autouse=True)
359366
def stop_driver(request):
360367
def fin():
361-
global driver_instance
362-
if driver_instance is not None:
363-
driver_instance.quit()
364-
driver_instance = None
368+
global selenium_driver
369+
if selenium_driver is not None:
370+
selenium_driver.stop_driver()
371+
selenium_driver = None
365372

366373
request.addfinalizer(fin)
367374

368375

369376
def pytest_exception_interact(node, call, report):
370377
if report.failed:
371-
global driver_instance
372-
if driver_instance is not None:
373-
driver_instance.quit()
374-
driver_instance = None
378+
global selenium_driver
379+
if selenium_driver is not None:
380+
selenium_driver.stop_driver()
381+
selenium_driver = None
375382

376383

377384
@pytest.fixture
@@ -399,7 +406,7 @@ def server(request):
399406
)
400407

401408
remote_env = os.environ.copy()
402-
if platform.system() == "Linux":
409+
if sys.platform == "linux":
403410
# There are issues with window size/position when running Firefox
404411
# under Wayland, so we use XWayland instead.
405412
remote_env["MOZ_ENABLE_WAYLAND"] = "0"

WebDriverTests/imported/selenium/py/selenium/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
# under the License.
1717

1818

19-
__version__ = "4.34.2"
19+
__version__ = "4.36.0.202508121825"

WebDriverTests/imported/selenium/py/selenium/webdriver/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from .wpewebkit.service import Service as WPEWebKitService # noqa
3131
from .wpewebkit.webdriver import WebDriver as WPEWebKit # noqa
3232

33-
__version__ = "4.34.2"
33+
__version__ = "4.36.0.202508121825"
3434

3535
# We need an explicit __all__ because the above won't otherwise be exported.
3636
__all__ = [

WebDriverTests/imported/selenium/py/selenium/webdriver/common/actions/action_builder.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
from typing import Optional, Union
18+
19+
from typing import Any, Optional, Union
1920

2021
from selenium.webdriver.remote.command import Command
2122

@@ -40,7 +41,7 @@ def __init__(
4041
mouse = mouse or PointerInput(interaction.POINTER_MOUSE, "mouse")
4142
keyboard = keyboard or KeyInput(interaction.KEY)
4243
wheel = wheel or WheelInput(interaction.WHEEL)
43-
self.devices = [mouse, keyboard, wheel]
44+
self.devices: list[Union[PointerInput, KeyInput, WheelInput]] = [mouse, keyboard, wheel]
4445
self._key_action = KeyActions(keyboard)
4546
self._pointer_action = PointerActions(mouse, duration=duration)
4647
self._wheel_action = WheelActions(wheel)
@@ -62,11 +63,11 @@ def get_device_with(self, name: str) -> Optional[Union["WheelInput", "PointerInp
6263

6364
@property
6465
def pointer_inputs(self) -> list[PointerInput]:
65-
return [device for device in self.devices if device.type == interaction.POINTER]
66+
return [device for device in self.devices if isinstance(device, PointerInput)]
6667

6768
@property
6869
def key_inputs(self) -> list[KeyInput]:
69-
return [device for device in self.devices if device.type == interaction.KEY]
70+
return [device for device in self.devices if isinstance(device, KeyInput)]
7071

7172
@property
7273
def key_action(self) -> KeyActions:
@@ -159,7 +160,7 @@ def perform(self) -> None:
159160
>>> el = driver.find_element(id: "some_id")
160161
>>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys("keys").perform()
161162
"""
162-
enc = {"actions": []}
163+
enc: dict[str, list[Any]] = {"actions": []}
163164
for device in self.devices:
164165
encoded = device.encode()
165166
if encoded["actions"]:

WebDriverTests/imported/selenium/py/selenium/webdriver/common/bidi/browser.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
# under the License.
1717

1818

19+
from typing import Any, Optional
20+
1921
from selenium.webdriver.common.bidi.common import command_builder
22+
from selenium.webdriver.common.bidi.session import UserPromptHandler
23+
from selenium.webdriver.common.proxy import Proxy
2024

2125

2226
class ClientWindowState:
@@ -182,14 +186,36 @@ class Browser:
182186
def __init__(self, conn):
183187
self.conn = conn
184188

185-
def create_user_context(self) -> str:
189+
def create_user_context(
190+
self,
191+
accept_insecure_certs: Optional[bool] = None,
192+
proxy: Optional[Proxy] = None,
193+
unhandled_prompt_behavior: Optional[UserPromptHandler] = None,
194+
) -> str:
186195
"""Creates a new user context.
187196
197+
Parameters:
198+
-----------
199+
accept_insecure_certs: Optional flag to accept insecure TLS certificates
200+
proxy: Optional proxy configuration for the user context
201+
unhandled_prompt_behavior: Optional configuration for handling user prompts
202+
188203
Returns:
189204
-------
190205
str: The ID of the created user context.
191206
"""
192-
result = self.conn.execute(command_builder("browser.createUserContext", {}))
207+
params: dict[str, Any] = {}
208+
209+
if accept_insecure_certs is not None:
210+
params["acceptInsecureCerts"] = accept_insecure_certs
211+
212+
if proxy is not None:
213+
params["proxy"] = proxy.to_bidi_dict()
214+
215+
if unhandled_prompt_behavior is not None:
216+
params["unhandledPromptBehavior"] = unhandled_prompt_behavior.to_dict()
217+
218+
result = self.conn.execute(command_builder("browser.createUserContext", params))
193219
return result["userContext"]
194220

195221
def get_user_contexts(self) -> list[str]:

0 commit comments

Comments
 (0)