Skip to content

Commit 23ccfc2

Browse files
mikahanninenclaude
andcommitted
fix: relax selenium exact pin to allow Appium 3 compatibility (#1312)
- Change `selenium==4.15.2` to `selenium>=4.15.2,<5.0.0` in packages/main - Bump rpaframework version 31.1.2 -> 31.2.0 - Upgrade selenium in main's lock file: 4.15.2 -> 4.41.0 - Add standalone EdgeDriver integration test (packages/core) that exercises the azureedge.net -> microsoft.com redirect fix from PR #1227 - Add two pytest regression tests: API import check and constraint pin guard Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6785bad commit 23ccfc2

5 files changed

Lines changed: 184 additions & 18 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/env python3
2+
"""Standalone EdgeDriver integration test for issue #1312.
3+
4+
Verifies that:
5+
1. EdgeDriver binary can be downloaded (tests azureedge.net -> microsoft.com
6+
redirect fix from PR #1227) — this is the primary test
7+
2. A headless Edge session can be started (end-to-end, requires Edge browser installed)
8+
9+
Expected to FAIL with selenium==4.15.2 exact pin (old azureedge.net CDN issues).
10+
Expected to PASS after fix: selenium>=4.15.2,<5.0.0 (newer version resolved).
11+
12+
Exit codes:
13+
0 — download succeeded (session also started if Edge browser is installed)
14+
1 — download or session failed unexpectedly
15+
16+
Usage:
17+
python test_edge_driver.py
18+
# or from packages/core directory:
19+
uv run python tests/python/test_edge_driver.py
20+
"""
21+
import shutil
22+
import sys
23+
from pathlib import Path
24+
25+
26+
def main() -> int:
27+
import importlib.metadata
28+
29+
selenium_ver = importlib.metadata.version("selenium")
30+
print(f"Selenium version: {selenium_ver}")
31+
32+
# Step 1: download EdgeDriver — exercises the azureedge.net redirect patch
33+
try:
34+
from RPA.core import webdriver
35+
36+
results_dir = Path(__file__).parent / "results"
37+
results_dir.mkdir(exist_ok=True)
38+
print("Downloading EdgeDriver...")
39+
driver_path = webdriver.download("Edge", root=results_dir)
40+
print(f" Driver downloaded: {driver_path}")
41+
except Exception as exc:
42+
print(f"\nFAIL (download): {type(exc).__name__}: {exc}")
43+
return 1
44+
45+
# Step 2: start a headless Edge session — requires Edge browser to be installed
46+
edge_binary = shutil.which("msedge") or shutil.which("microsoft-edge")
47+
if not edge_binary:
48+
# Also check the standard macOS application path
49+
macos_edge = Path("/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge")
50+
if macos_edge.exists():
51+
edge_binary = str(macos_edge)
52+
53+
if not edge_binary:
54+
print(
55+
"\nPASS (download only): EdgeDriver downloaded successfully. "
56+
"Edge browser not installed — skipping session test."
57+
)
58+
return 0
59+
60+
try:
61+
from selenium import webdriver as selenium_webdriver
62+
from selenium.webdriver import EdgeOptions
63+
from selenium.webdriver.edge.service import Service
64+
65+
options = EdgeOptions()
66+
options.add_argument("--headless=new")
67+
options.add_argument("--no-sandbox")
68+
options.add_argument("--disable-dev-shm-usage")
69+
options.binary_location = edge_binary
70+
service = Service(driver_path)
71+
print(f"Starting headless Edge session (binary: {edge_binary})...")
72+
driver = selenium_webdriver.Edge(service=service, options=options)
73+
try:
74+
driver.get("about:blank")
75+
title = driver.title
76+
finally:
77+
driver.quit()
78+
print(f" Session OK, page title: '{title}'")
79+
except Exception as exc:
80+
print(f"\nFAIL (session): {type(exc).__name__}: {exc}")
81+
return 1
82+
83+
print("\nPASS: EdgeDriver download and session both work correctly.")
84+
return 0
85+
86+
87+
if __name__ == "__main__":
88+
sys.exit(main())

packages/main/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "rpaframework"
3-
version = "31.1.2"
3+
version = "31.2.0"
44
description = "A collection of tools and libraries for RPA"
55
authors = [{name = "RPA Framework", email = "rpafw@robocorp.com"}]
66
license = {text = "Apache-2.0"}
@@ -60,7 +60,7 @@ dependencies = [
6060
"mss>=6.0.0",
6161
"chardet>=3.0.0",
6262
"PySocks>=1.5.6,!=1.5.7,<2.0.0",
63-
"selenium==4.15.2",
63+
"selenium>=4.15.2,<5.0.0",
6464
"click>=8.1.2",
6565
"PyYAML>=5.4.1,<7.0.0",
6666
"tenacity>=8.0.1",

packages/main/tests/python/test_browser.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,47 @@ def test_custom_options(self, library):
8484
assert options_obj.binary_location == path
8585

8686

87+
def test_selenium_api_imports():
88+
"""All selenium APIs used by RPA.Browser.Selenium must remain importable.
89+
90+
Regression guard: if a newer selenium 4.x removes any of these, this test fails
91+
before the constraint is widened further.
92+
"""
93+
from selenium.common import WebDriverException # noqa: F401
94+
from selenium.common.exceptions import ElementClickInterceptedException # noqa: F401
95+
from selenium.webdriver import ( # noqa: F401
96+
ChromeOptions,
97+
EdgeOptions,
98+
FirefoxOptions,
99+
FirefoxProfile,
100+
IeOptions,
101+
)
102+
from selenium.webdriver.common.by import By # noqa: F401
103+
from selenium.webdriver.common.options import ArgOptions # noqa: F401
104+
from selenium.webdriver.remote.shadowroot import ShadowRoot # noqa: F401
105+
from selenium.webdriver.support import expected_conditions # noqa: F401
106+
from selenium.webdriver.support.ui import WebDriverWait # noqa: F401
107+
108+
109+
def test_selenium_constraint_is_not_exact_pin():
110+
"""Regression: selenium must not be pinned to an exact version (issue #1312).
111+
112+
An exact selenium==x.y.z pin blocks users from installing packages that require
113+
a different selenium version (e.g. appium-python-client for Appium 3).
114+
"""
115+
import re
116+
from pathlib import Path
117+
118+
pyproject = (Path(__file__).parent.parent.parent / "pyproject.toml").read_text()
119+
match = re.search(r'"selenium([^"]*)"', pyproject)
120+
assert match, "selenium dependency not found in pyproject.toml"
121+
constraint = match.group(1)
122+
assert not constraint.startswith("=="), (
123+
f"selenium must not be exact-pinned; got 'selenium{constraint}'. "
124+
"Exact pins block Appium 3 and other selenium-dependent packages (issue #1312)."
125+
)
126+
127+
87128
@pytest.mark.parametrize(
88129
"url,default,scheme",
89130
[

packages/main/uv.lock

Lines changed: 47 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

uv.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)