Skip to content

Upgrade selenium and Mobile Mode #2175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion help_docs/ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,13 @@

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

<div><a href="https://seleniumbase.io/coffee/"><b>Coffee Cart (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/demo_page"><b>Demo Page (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/simple/login"><b>Simple App (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/realworld/login"><b>MFA Login (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/tinymce/"><b>TinyMCE (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/error_page/"><b>Error Page (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/other/drag_and_drop"><b>Drag-&-Drop (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/other/drag_and_drop"><b>Drag & Drop (Test Page)</b></a></div>
<div><a href="https://seleniumbase.io/devices/"><b>Device Farm (Virtual)</b></a></div>
<div><a href="https://seleniumbase.io/w3schools/"><b>HTML Playground Page</b></a></div>
<div><a href="https://seleniumbase.io/w3schools/sbase"><b>SeleniumBase in iframe</b></a></div>
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ nav:
- Demo Pages:
- 🍵 Coffee Cart (Test App): https://seleniumbase.io/coffee/
- 📑 Demo Page (Test Page): https://seleniumbase.io/demo_page
- 🔑 Simple App (Test Page): https://seleniumbase.io/simple/login
- 🔑 MFA Login (Test App): https://seleniumbase.io/realworld/login
- 📝 TinyMCE (Test Page): https://seleniumbase.io/tinymce/
- 🔢 Calculator (Test App): https://seleniumbase.io/apps/calculator
Expand Down
2 changes: 1 addition & 1 deletion mkdocs_build/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ paginate==0.5.6
pyquery==2.0.0
readtime==3.0.0
mkdocs==1.5.3
mkdocs-material==9.4.4
mkdocs-material==9.4.5
mkdocs-exclude-search==0.6.5
mkdocs-simple-hooks==0.1.5
mkdocs-material-extensions==1.2
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ trio==0.22.2
trio-websocket==0.11.1
wsproto==1.2.0
selenium==4.11.2;python_version<"3.8"
selenium==4.13.0;python_version>="3.8"
selenium==4.14.0;python_version>="3.8"
cssselect==1.2.0
sortedcontainers==2.4.0
fasteners==0.19
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# seleniumbase package
__version__ = "4.19.2"
__version__ = "4.20.0"
97 changes: 85 additions & 12 deletions seleniumbase/core/browser_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,15 @@ def has_cf(text):
return False


def uc_special_open_if_cf(driver, url, proxy_string=None):
def uc_special_open_if_cf(
driver,
url,
proxy_string=None,
mobile_emulator=None,
device_width=None,
device_height=None,
device_pixel_ratio=None,
):
if (
url.startswith("http:") or url.startswith("https:")
):
Expand All @@ -345,6 +353,36 @@ def uc_special_open_if_cf(driver, url, proxy_string=None):
driver.close()
driver.switch_to.window(driver.window_handles[-1])
time.sleep(0.02)
if mobile_emulator:
uc_metrics = {}
if (
type(device_width) is int
and type(device_height) is int
and type(device_pixel_ratio) is int
):
uc_metrics["width"] = device_width
uc_metrics["height"] = device_height
uc_metrics["pixelRatio"] = device_pixel_ratio
else:
uc_metrics["width"] = constants.Mobile.WIDTH
uc_metrics["height"] = constants.Mobile.HEIGHT
uc_metrics["pixelRatio"] = constants.Mobile.RATIO
set_device_metrics_override = dict(
{
"width": uc_metrics["width"],
"height": uc_metrics["height"],
"deviceScaleFactor": uc_metrics["pixelRatio"],
"mobile": True
}
)
try:
driver.execute_cdp_cmd(
'Emulation.setDeviceMetricsOverride',
set_device_metrics_override
)
except Exception:
pass
time.sleep(0.03)
else:
driver.default_get(url) # The original one
else:
Expand Down Expand Up @@ -739,7 +777,7 @@ def _set_chrome_options(
"excludeSwitches",
["enable-automation", "enable-logging", "enable-blink-features"],
)
if mobile_emulator:
if mobile_emulator and not is_using_uc(undetectable, browser_name):
emulator_settings = {}
device_metrics = {}
if (
Expand All @@ -751,9 +789,9 @@ def _set_chrome_options(
device_metrics["height"] = device_height
device_metrics["pixelRatio"] = device_pixel_ratio
else:
device_metrics["width"] = 360
device_metrics["height"] = 640
device_metrics["pixelRatio"] = 2
device_metrics["width"] = constants.Mobile.WIDTH
device_metrics["height"] = constants.Mobile.HEIGHT
device_metrics["pixelRatio"] = constants.Mobile.RATIO
emulator_settings["deviceMetrics"] = device_metrics
if user_agent:
emulator_settings["userAgent"] = user_agent
Expand Down Expand Up @@ -1279,8 +1317,8 @@ def get_driver(
if (uc_cdp_events or uc_subprocess) and not undetectable:
undetectable = True
if is_using_uc(undetectable, browser_name) and mobile_emulator:
mobile_emulator = False
user_agent = None
if not user_agent:
user_agent = constants.Mobile.AGENT
if page_load_strategy and page_load_strategy.lower() == "none":
settings.PAGE_LOAD_STRATEGY = "none"
proxy_auth = False
Expand Down Expand Up @@ -2359,7 +2397,7 @@ def get_local_driver(
elif headless:
if "--headless" not in edge_options.arguments:
edge_options.add_argument("--headless")
if mobile_emulator:
if mobile_emulator and not is_using_uc(undetectable, browser_name):
emulator_settings = {}
device_metrics = {}
if (
Expand All @@ -2371,9 +2409,9 @@ def get_local_driver(
device_metrics["height"] = device_height
device_metrics["pixelRatio"] = device_pixel_ratio
else:
device_metrics["width"] = 360
device_metrics["height"] = 640
device_metrics["pixelRatio"] = 2
device_metrics["width"] = constants.Mobile.WIDTH
device_metrics["height"] = constants.Mobile.HEIGHT
device_metrics["pixelRatio"] = constants.Mobile.RATIO
emulator_settings["deviceMetrics"] = device_metrics
if user_agent:
emulator_settings["userAgent"] = user_agent
Expand Down Expand Up @@ -3416,7 +3454,13 @@ def get_local_driver(
driver.default_get = driver.get # Save copy of original
if uc_activated:
driver.get = lambda url: uc_special_open_if_cf(
driver, url, proxy_string
driver,
url,
proxy_string,
mobile_emulator,
device_width,
device_height,
device_pixel_ratio,
)
driver.uc_open = lambda url: uc_open(driver, url)
driver.uc_open_with_tab = (
Expand All @@ -3425,6 +3469,35 @@ def get_local_driver(
driver.uc_open_with_reconnect = (
lambda url: uc_open_with_reconnect(driver, url)
)
if mobile_emulator:
uc_metrics = {}
if (
type(device_width) is int
and type(device_height) is int
and type(device_pixel_ratio) is int
):
uc_metrics["width"] = device_width
uc_metrics["height"] = device_height
uc_metrics["pixelRatio"] = device_pixel_ratio
else:
uc_metrics["width"] = constants.Mobile.WIDTH
uc_metrics["height"] = constants.Mobile.HEIGHT
uc_metrics["pixelRatio"] = constants.Mobile.RATIO
set_device_metrics_override = dict(
{
"width": uc_metrics["width"],
"height": uc_metrics["height"],
"deviceScaleFactor": uc_metrics["pixelRatio"],
"mobile": True
}
)
try:
driver.execute_cdp_cmd(
'Emulation.setDeviceMetricsOverride',
set_device_metrics_override
)
except Exception:
pass
return extend_driver(driver)
else: # Running headless on Linux (and not using --uc)
try:
Expand Down
29 changes: 12 additions & 17 deletions seleniumbase/fixtures/base_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -3887,12 +3887,8 @@ def get_new_driver(
if d_p_r is None:
d_p_r = self.__device_pixel_ratio
if is_mobile and not user_agent:
# Use the Pixel 4 user agent by default if not specified
user_agent = (
"Mozilla/5.0 (Linux; Android 11; Pixel 4 XL) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/89.0.4389.105 Mobile Safari/537.36"
)
# Use a Pixel user agent by default if not specified
user_agent = constants.Mobile.AGENT
valid_browsers = constants.ValidBrowsers.valid_browsers
if browser_name not in valid_browsers:
raise Exception(
Expand Down Expand Up @@ -14351,15 +14347,9 @@ def setUp(self, masterqa_mode=False):
self.mobile_emulator = True
except Exception:
raise Exception(exception_string)
if self.mobile_emulator:
if not self.user_agent:
# Use the Pixel 4 user agent by default if not specified
self.user_agent = (
"Mozilla/5.0 (Linux; Android 11; Pixel 4 XL) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/89.0.4389.105 Mobile Safari/537.36"
)

if self.mobile_emulator and not self.user_agent:
# Use a Pixel user agent by default if not specified
self.user_agent = constants.Mobile.AGENT
if self.browser in ["firefox", "ie", "safari"]:
# The Recorder Mode browser extension is only for Chrome/Edge.
if self.recorder_mode:
Expand Down Expand Up @@ -15314,11 +15304,11 @@ def __activate_sb_mgr_post_mortem_debug_mode(self):
# Post Mortem Debug Mode ("python --pdb")

def __activate_debug_mode_in_teardown(self):
"""Activate Debug Mode in tearDown() when using "--final-debug"."""
"""Activate Final Trace / Debug Mode"""
import pdb

pdb.set_trace()
# Final Debug Mode ("--final-debug")
# Final Trace ("--ftrace")

def has_exception(self):
"""(This method should ONLY be used in custom tearDown() methods.)
Expand Down Expand Up @@ -15813,6 +15803,11 @@ def tearDown(self):
and sb_config._do_sb_post_mortem
):
self.__activate_sb_mgr_post_mortem_debug_mode()
elif (
hasattr(sb_config, "_do_sb_final_trace")
and sb_config._do_sb_final_trace
):
self.__activate_debug_mode_in_teardown()
# (Pynose / Behave / Pure Python) Close all open browser windows
self.__quit_all_drivers()
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
Expand Down
13 changes: 13 additions & 0 deletions seleniumbase/fixtures/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,19 @@ class SeleniumWire:
VER = "5.1.0"


class Mobile:
# Default values for mobile settings
WIDTH = 390
HEIGHT = 715
RATIO = 3
AGENT = (
"Mozilla/5.0 (Linux; Android 13; Pixel 7 XL "
"Build/SP2A.220505.006.A1; wv) "
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 "
"Chrome/110.0.5028.105 Mobile Safari/537.36"
)


class ValidBrowsers:
valid_browsers = [
"chrome",
Expand Down
2 changes: 1 addition & 1 deletion seleniumbase/fixtures/js_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ def post_messenger_success_message(driver, message, msg_dur=None):
theme = "future"
location = "bottom_right"
if hasattr(sb_config, "mobile_emulator") and sb_config.mobile_emulator:
location = "top_center"
location = "top_right"
set_messenger_theme(driver, theme=theme, location=location)
post_message(driver, message, msg_dur, style="success")
time.sleep(msg_dur + 0.07)
Expand Down
3 changes: 0 additions & 3 deletions seleniumbase/plugins/driver_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,9 +341,6 @@ def Driver(
uc_cdp_events = True
else:
uc_cdp_events = False
if undetectable and is_mobile:
is_mobile = False
user_agent = None
if use_auto_ext is None:
if "--use-auto-ext" in sys_argv:
use_auto_ext = True
Expand Down
6 changes: 1 addition & 5 deletions seleniumbase/plugins/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ def pytest_addoption(parser):
help="""Designates the three device metrics of the mobile
emulator: CSS Width, CSS Height, and Pixel-Ratio.
Format: A comma-separated string with the 3 values.
Example: "375,734,3"
Examples: "375,734,5" or "411,731,3" or "390,715,3"
Default: None. (Will use default values if None)""",
)
parser.addoption(
Expand Down Expand Up @@ -1399,10 +1399,6 @@ def pytest_addoption(parser):
"\n If you need both, override get_new_driver() from BaseCase:"
"\n https://seleniumbase.io/help_docs/syntax_formats/#sb_sf_09\n"
)
if undetectable and "--mobile" in sys_argv:
raise Exception(
"\n SeleniumBase doesn't support mixing --uc with --mobile\n"
)


def pytest_configure(config):
Expand Down
13 changes: 9 additions & 4 deletions seleniumbase/plugins/sb_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,8 @@ def SB(
is_mobile = True
else:
is_mobile = False
if is_mobile:
sb_config.mobile_emulator = True
proxy_string = proxy
user_agent = agent
recorder_mode = False
Expand Down Expand Up @@ -370,7 +372,6 @@ def SB(
sb_config.proxy_driver = True
if variables and type(variables) is str and len(variables) > 0:
import ast

bad_input = False
if (
not variables.startswith("{")
Expand Down Expand Up @@ -458,9 +459,6 @@ def SB(
uc_cdp_events = True
else:
uc_cdp_events = False
if undetectable and is_mobile:
is_mobile = False
user_agent = None
if use_auto_ext is None:
if "--use-auto-ext" in sys_argv:
use_auto_ext = True
Expand Down Expand Up @@ -875,6 +873,13 @@ def SB(
finally:
if sb._has_failure and "--pdb" in sys_argv:
sb_config._do_sb_post_mortem = True
elif (
"--final-debug" in sys_argv
or "--final-trace" in sys_argv
or "--fdebug" in sys_argv
or "--ftrace" in sys_argv
):
sb_config._do_sb_final_trace = True
try:
sb.tearDown()
except Exception as t_e:
Expand Down
13 changes: 2 additions & 11 deletions seleniumbase/plugins/selenium_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def options(self, parser, env):
help="""Designates the three device metrics of the mobile
emulator: CSS Width, CSS Height, and Pixel-Ratio.
Format: A comma-separated string with the 3 values.
Example: "375,734,3"
Examples: "375,734,5" or "411,731,3" or "390,715,3"
Default: None. (Will use default values if None)""",
)
parser.addoption(
Expand Down Expand Up @@ -1163,16 +1163,6 @@ def beforeTest(self, test):
)
self.options.use_wire = False
test.test.use_wire = False
if self.options.mobile_emulator and self.options.undetectable:
print(
"\n"
"SeleniumBase doesn't support mixing --uc with --mobile.\n"
"(Only UC Mode without Mobile will be used for this run)\n"
)
self.options.mobile_emulator = False
test.test.mobile_emulator = False
self.options.user_agent = None
test.test.user_agent = None
# Recorder Mode can still optimize scripts in --headless2 mode.
if self.options.recorder_mode and self.options.headless:
self.options.headless = False
Expand Down Expand Up @@ -1205,6 +1195,7 @@ def beforeTest(self, test):
sb_config._SMALL_TIMEOUT = settings.SMALL_TIMEOUT
sb_config._LARGE_TIMEOUT = settings.LARGE_TIMEOUT
sb_config._context_of_runner = False # Context Manager Compatibility
sb_config.mobile_emulator = self.options.mobile_emulator
sb_config.proxy_driver = self.options.proxy_driver
sb_config.multi_proxy = self.options.multi_proxy
# The driver will be received later
Expand Down
Loading