Skip to content

Commit cd66f4a

Browse files
authored
Merge pull request #2175 from seleniumbase/upgrade-selenium-and-mobile-mode
Upgrade `selenium` and Mobile Mode
2 parents 310697d + 4561d9d commit cd66f4a

15 files changed

+137
-69
lines changed

help_docs/ReadMe.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,13 @@
8181

8282
<h3>Demo Pages / Web Examples</h3>
8383

84+
<div><a href="https://seleniumbase.io/coffee/"><b>Coffee Cart (Test Page)</b></a></div>
8485
<div><a href="https://seleniumbase.io/demo_page"><b>Demo Page (Test Page)</b></a></div>
86+
<div><a href="https://seleniumbase.io/simple/login"><b>Simple App (Test Page)</b></a></div>
8587
<div><a href="https://seleniumbase.io/realworld/login"><b>MFA Login (Test Page)</b></a></div>
8688
<div><a href="https://seleniumbase.io/tinymce/"><b>TinyMCE (Test Page)</b></a></div>
8789
<div><a href="https://seleniumbase.io/error_page/"><b>Error Page (Test Page)</b></a></div>
88-
<div><a href="https://seleniumbase.io/other/drag_and_drop"><b>Drag-&-Drop (Test Page)</b></a></div>
90+
<div><a href="https://seleniumbase.io/other/drag_and_drop"><b>Drag & Drop (Test Page)</b></a></div>
8991
<div><a href="https://seleniumbase.io/devices/"><b>Device Farm (Virtual)</b></a></div>
9092
<div><a href="https://seleniumbase.io/w3schools/"><b>HTML Playground Page</b></a></div>
9193
<div><a href="https://seleniumbase.io/w3schools/sbase"><b>SeleniumBase in iframe</b></a></div>

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ nav:
133133
- Demo Pages:
134134
- 🍵 Coffee Cart (Test App): https://seleniumbase.io/coffee/
135135
- 📑 Demo Page (Test Page): https://seleniumbase.io/demo_page
136+
- 🔑 Simple App (Test Page): https://seleniumbase.io/simple/login
136137
- 🔑 MFA Login (Test App): https://seleniumbase.io/realworld/login
137138
- 📝 TinyMCE (Test Page): https://seleniumbase.io/tinymce/
138139
- 🔢 Calculator (Test App): https://seleniumbase.io/apps/calculator

mkdocs_build/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ paginate==0.5.6
2020
pyquery==2.0.0
2121
readtime==3.0.0
2222
mkdocs==1.5.3
23-
mkdocs-material==9.4.4
23+
mkdocs-material==9.4.5
2424
mkdocs-exclude-search==0.6.5
2525
mkdocs-simple-hooks==0.1.5
2626
mkdocs-material-extensions==1.2

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ trio==0.22.2
2525
trio-websocket==0.11.1
2626
wsproto==1.2.0
2727
selenium==4.11.2;python_version<"3.8"
28-
selenium==4.13.0;python_version>="3.8"
28+
selenium==4.14.0;python_version>="3.8"
2929
cssselect==1.2.0
3030
sortedcontainers==2.4.0
3131
fasteners==0.19

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.19.2"
2+
__version__ = "4.20.0"

seleniumbase/core/browser_launcher.py

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,15 @@ def has_cf(text):
319319
return False
320320

321321

322-
def uc_special_open_if_cf(driver, url, proxy_string=None):
322+
def uc_special_open_if_cf(
323+
driver,
324+
url,
325+
proxy_string=None,
326+
mobile_emulator=None,
327+
device_width=None,
328+
device_height=None,
329+
device_pixel_ratio=None,
330+
):
323331
if (
324332
url.startswith("http:") or url.startswith("https:")
325333
):
@@ -345,6 +353,36 @@ def uc_special_open_if_cf(driver, url, proxy_string=None):
345353
driver.close()
346354
driver.switch_to.window(driver.window_handles[-1])
347355
time.sleep(0.02)
356+
if mobile_emulator:
357+
uc_metrics = {}
358+
if (
359+
type(device_width) is int
360+
and type(device_height) is int
361+
and type(device_pixel_ratio) is int
362+
):
363+
uc_metrics["width"] = device_width
364+
uc_metrics["height"] = device_height
365+
uc_metrics["pixelRatio"] = device_pixel_ratio
366+
else:
367+
uc_metrics["width"] = constants.Mobile.WIDTH
368+
uc_metrics["height"] = constants.Mobile.HEIGHT
369+
uc_metrics["pixelRatio"] = constants.Mobile.RATIO
370+
set_device_metrics_override = dict(
371+
{
372+
"width": uc_metrics["width"],
373+
"height": uc_metrics["height"],
374+
"deviceScaleFactor": uc_metrics["pixelRatio"],
375+
"mobile": True
376+
}
377+
)
378+
try:
379+
driver.execute_cdp_cmd(
380+
'Emulation.setDeviceMetricsOverride',
381+
set_device_metrics_override
382+
)
383+
except Exception:
384+
pass
385+
time.sleep(0.03)
348386
else:
349387
driver.default_get(url) # The original one
350388
else:
@@ -739,7 +777,7 @@ def _set_chrome_options(
739777
"excludeSwitches",
740778
["enable-automation", "enable-logging", "enable-blink-features"],
741779
)
742-
if mobile_emulator:
780+
if mobile_emulator and not is_using_uc(undetectable, browser_name):
743781
emulator_settings = {}
744782
device_metrics = {}
745783
if (
@@ -751,9 +789,9 @@ def _set_chrome_options(
751789
device_metrics["height"] = device_height
752790
device_metrics["pixelRatio"] = device_pixel_ratio
753791
else:
754-
device_metrics["width"] = 360
755-
device_metrics["height"] = 640
756-
device_metrics["pixelRatio"] = 2
792+
device_metrics["width"] = constants.Mobile.WIDTH
793+
device_metrics["height"] = constants.Mobile.HEIGHT
794+
device_metrics["pixelRatio"] = constants.Mobile.RATIO
757795
emulator_settings["deviceMetrics"] = device_metrics
758796
if user_agent:
759797
emulator_settings["userAgent"] = user_agent
@@ -1279,8 +1317,8 @@ def get_driver(
12791317
if (uc_cdp_events or uc_subprocess) and not undetectable:
12801318
undetectable = True
12811319
if is_using_uc(undetectable, browser_name) and mobile_emulator:
1282-
mobile_emulator = False
1283-
user_agent = None
1320+
if not user_agent:
1321+
user_agent = constants.Mobile.AGENT
12841322
if page_load_strategy and page_load_strategy.lower() == "none":
12851323
settings.PAGE_LOAD_STRATEGY = "none"
12861324
proxy_auth = False
@@ -2359,7 +2397,7 @@ def get_local_driver(
23592397
elif headless:
23602398
if "--headless" not in edge_options.arguments:
23612399
edge_options.add_argument("--headless")
2362-
if mobile_emulator:
2400+
if mobile_emulator and not is_using_uc(undetectable, browser_name):
23632401
emulator_settings = {}
23642402
device_metrics = {}
23652403
if (
@@ -2371,9 +2409,9 @@ def get_local_driver(
23712409
device_metrics["height"] = device_height
23722410
device_metrics["pixelRatio"] = device_pixel_ratio
23732411
else:
2374-
device_metrics["width"] = 360
2375-
device_metrics["height"] = 640
2376-
device_metrics["pixelRatio"] = 2
2412+
device_metrics["width"] = constants.Mobile.WIDTH
2413+
device_metrics["height"] = constants.Mobile.HEIGHT
2414+
device_metrics["pixelRatio"] = constants.Mobile.RATIO
23772415
emulator_settings["deviceMetrics"] = device_metrics
23782416
if user_agent:
23792417
emulator_settings["userAgent"] = user_agent
@@ -3416,7 +3454,13 @@ def get_local_driver(
34163454
driver.default_get = driver.get # Save copy of original
34173455
if uc_activated:
34183456
driver.get = lambda url: uc_special_open_if_cf(
3419-
driver, url, proxy_string
3457+
driver,
3458+
url,
3459+
proxy_string,
3460+
mobile_emulator,
3461+
device_width,
3462+
device_height,
3463+
device_pixel_ratio,
34203464
)
34213465
driver.uc_open = lambda url: uc_open(driver, url)
34223466
driver.uc_open_with_tab = (
@@ -3425,6 +3469,35 @@ def get_local_driver(
34253469
driver.uc_open_with_reconnect = (
34263470
lambda url: uc_open_with_reconnect(driver, url)
34273471
)
3472+
if mobile_emulator:
3473+
uc_metrics = {}
3474+
if (
3475+
type(device_width) is int
3476+
and type(device_height) is int
3477+
and type(device_pixel_ratio) is int
3478+
):
3479+
uc_metrics["width"] = device_width
3480+
uc_metrics["height"] = device_height
3481+
uc_metrics["pixelRatio"] = device_pixel_ratio
3482+
else:
3483+
uc_metrics["width"] = constants.Mobile.WIDTH
3484+
uc_metrics["height"] = constants.Mobile.HEIGHT
3485+
uc_metrics["pixelRatio"] = constants.Mobile.RATIO
3486+
set_device_metrics_override = dict(
3487+
{
3488+
"width": uc_metrics["width"],
3489+
"height": uc_metrics["height"],
3490+
"deviceScaleFactor": uc_metrics["pixelRatio"],
3491+
"mobile": True
3492+
}
3493+
)
3494+
try:
3495+
driver.execute_cdp_cmd(
3496+
'Emulation.setDeviceMetricsOverride',
3497+
set_device_metrics_override
3498+
)
3499+
except Exception:
3500+
pass
34283501
return extend_driver(driver)
34293502
else: # Running headless on Linux (and not using --uc)
34303503
try:

seleniumbase/fixtures/base_case.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3887,12 +3887,8 @@ def get_new_driver(
38873887
if d_p_r is None:
38883888
d_p_r = self.__device_pixel_ratio
38893889
if is_mobile and not user_agent:
3890-
# Use the Pixel 4 user agent by default if not specified
3891-
user_agent = (
3892-
"Mozilla/5.0 (Linux; Android 11; Pixel 4 XL) "
3893-
"AppleWebKit/537.36 (KHTML, like Gecko) "
3894-
"Chrome/89.0.4389.105 Mobile Safari/537.36"
3895-
)
3890+
# Use a Pixel user agent by default if not specified
3891+
user_agent = constants.Mobile.AGENT
38963892
valid_browsers = constants.ValidBrowsers.valid_browsers
38973893
if browser_name not in valid_browsers:
38983894
raise Exception(
@@ -14351,15 +14347,9 @@ def setUp(self, masterqa_mode=False):
1435114347
self.mobile_emulator = True
1435214348
except Exception:
1435314349
raise Exception(exception_string)
14354-
if self.mobile_emulator:
14355-
if not self.user_agent:
14356-
# Use the Pixel 4 user agent by default if not specified
14357-
self.user_agent = (
14358-
"Mozilla/5.0 (Linux; Android 11; Pixel 4 XL) "
14359-
"AppleWebKit/537.36 (KHTML, like Gecko) "
14360-
"Chrome/89.0.4389.105 Mobile Safari/537.36"
14361-
)
14362-
14350+
if self.mobile_emulator and not self.user_agent:
14351+
# Use a Pixel user agent by default if not specified
14352+
self.user_agent = constants.Mobile.AGENT
1436314353
if self.browser in ["firefox", "ie", "safari"]:
1436414354
# The Recorder Mode browser extension is only for Chrome/Edge.
1436514355
if self.recorder_mode:
@@ -15314,11 +15304,11 @@ def __activate_sb_mgr_post_mortem_debug_mode(self):
1531415304
# Post Mortem Debug Mode ("python --pdb")
1531515305

1531615306
def __activate_debug_mode_in_teardown(self):
15317-
"""Activate Debug Mode in tearDown() when using "--final-debug"."""
15307+
"""Activate Final Trace / Debug Mode"""
1531815308
import pdb
1531915309

1532015310
pdb.set_trace()
15321-
# Final Debug Mode ("--final-debug")
15311+
# Final Trace ("--ftrace")
1532215312

1532315313
def has_exception(self):
1532415314
"""(This method should ONLY be used in custom tearDown() methods.)
@@ -15813,6 +15803,11 @@ def tearDown(self):
1581315803
and sb_config._do_sb_post_mortem
1581415804
):
1581515805
self.__activate_sb_mgr_post_mortem_debug_mode()
15806+
elif (
15807+
hasattr(sb_config, "_do_sb_final_trace")
15808+
and sb_config._do_sb_final_trace
15809+
):
15810+
self.__activate_debug_mode_in_teardown()
1581615811
# (Pynose / Behave / Pure Python) Close all open browser windows
1581715812
self.__quit_all_drivers()
1581815813
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)

seleniumbase/fixtures/constants.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,19 @@ class SeleniumWire:
346346
VER = "5.1.0"
347347

348348

349+
class Mobile:
350+
# Default values for mobile settings
351+
WIDTH = 390
352+
HEIGHT = 715
353+
RATIO = 3
354+
AGENT = (
355+
"Mozilla/5.0 (Linux; Android 13; Pixel 7 XL "
356+
"Build/SP2A.220505.006.A1; wv) "
357+
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 "
358+
"Chrome/110.0.5028.105 Mobile Safari/537.36"
359+
)
360+
361+
349362
class ValidBrowsers:
350363
valid_browsers = [
351364
"chrome",

seleniumbase/fixtures/js_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ def post_messenger_success_message(driver, message, msg_dur=None):
910910
theme = "future"
911911
location = "bottom_right"
912912
if hasattr(sb_config, "mobile_emulator") and sb_config.mobile_emulator:
913-
location = "top_center"
913+
location = "top_right"
914914
set_messenger_theme(driver, theme=theme, location=location)
915915
post_message(driver, message, msg_dur, style="success")
916916
time.sleep(msg_dur + 0.07)

seleniumbase/plugins/driver_manager.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,6 @@ def Driver(
341341
uc_cdp_events = True
342342
else:
343343
uc_cdp_events = False
344-
if undetectable and is_mobile:
345-
is_mobile = False
346-
user_agent = None
347344
if use_auto_ext is None:
348345
if "--use-auto-ext" in sys_argv:
349346
use_auto_ext = True

seleniumbase/plugins/pytest_plugin.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,7 @@ def pytest_addoption(parser):
554554
help="""Designates the three device metrics of the mobile
555555
emulator: CSS Width, CSS Height, and Pixel-Ratio.
556556
Format: A comma-separated string with the 3 values.
557-
Example: "375,734,3"
557+
Examples: "375,734,5" or "411,731,3" or "390,715,3"
558558
Default: None. (Will use default values if None)""",
559559
)
560560
parser.addoption(
@@ -1399,10 +1399,6 @@ def pytest_addoption(parser):
13991399
"\n If you need both, override get_new_driver() from BaseCase:"
14001400
"\n https://seleniumbase.io/help_docs/syntax_formats/#sb_sf_09\n"
14011401
)
1402-
if undetectable and "--mobile" in sys_argv:
1403-
raise Exception(
1404-
"\n SeleniumBase doesn't support mixing --uc with --mobile\n"
1405-
)
14061402

14071403

14081404
def pytest_configure(config):

seleniumbase/plugins/sb_manager.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ def SB(
308308
is_mobile = True
309309
else:
310310
is_mobile = False
311+
if is_mobile:
312+
sb_config.mobile_emulator = True
311313
proxy_string = proxy
312314
user_agent = agent
313315
recorder_mode = False
@@ -370,7 +372,6 @@ def SB(
370372
sb_config.proxy_driver = True
371373
if variables and type(variables) is str and len(variables) > 0:
372374
import ast
373-
374375
bad_input = False
375376
if (
376377
not variables.startswith("{")
@@ -458,9 +459,6 @@ def SB(
458459
uc_cdp_events = True
459460
else:
460461
uc_cdp_events = False
461-
if undetectable and is_mobile:
462-
is_mobile = False
463-
user_agent = None
464462
if use_auto_ext is None:
465463
if "--use-auto-ext" in sys_argv:
466464
use_auto_ext = True
@@ -875,6 +873,13 @@ def SB(
875873
finally:
876874
if sb._has_failure and "--pdb" in sys_argv:
877875
sb_config._do_sb_post_mortem = True
876+
elif (
877+
"--final-debug" in sys_argv
878+
or "--final-trace" in sys_argv
879+
or "--fdebug" in sys_argv
880+
or "--ftrace" in sys_argv
881+
):
882+
sb_config._do_sb_final_trace = True
878883
try:
879884
sb.tearDown()
880885
except Exception as t_e:

seleniumbase/plugins/selenium_plugin.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ def options(self, parser, env):
296296
help="""Designates the three device metrics of the mobile
297297
emulator: CSS Width, CSS Height, and Pixel-Ratio.
298298
Format: A comma-separated string with the 3 values.
299-
Example: "375,734,3"
299+
Examples: "375,734,5" or "411,731,3" or "390,715,3"
300300
Default: None. (Will use default values if None)""",
301301
)
302302
parser.addoption(
@@ -1163,16 +1163,6 @@ def beforeTest(self, test):
11631163
)
11641164
self.options.use_wire = False
11651165
test.test.use_wire = False
1166-
if self.options.mobile_emulator and self.options.undetectable:
1167-
print(
1168-
"\n"
1169-
"SeleniumBase doesn't support mixing --uc with --mobile.\n"
1170-
"(Only UC Mode without Mobile will be used for this run)\n"
1171-
)
1172-
self.options.mobile_emulator = False
1173-
test.test.mobile_emulator = False
1174-
self.options.user_agent = None
1175-
test.test.user_agent = None
11761166
# Recorder Mode can still optimize scripts in --headless2 mode.
11771167
if self.options.recorder_mode and self.options.headless:
11781168
self.options.headless = False
@@ -1205,6 +1195,7 @@ def beforeTest(self, test):
12051195
sb_config._SMALL_TIMEOUT = settings.SMALL_TIMEOUT
12061196
sb_config._LARGE_TIMEOUT = settings.LARGE_TIMEOUT
12071197
sb_config._context_of_runner = False # Context Manager Compatibility
1198+
sb_config.mobile_emulator = self.options.mobile_emulator
12081199
sb_config.proxy_driver = self.options.proxy_driver
12091200
sb_config.multi_proxy = self.options.multi_proxy
12101201
# The driver will be received later

0 commit comments

Comments
 (0)