seleniumbase 4.33.4__py3-none-any.whl → 4.34.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +10 -2
- seleniumbase/console_scripts/run.py +6 -2
- seleniumbase/console_scripts/sb_commander.py +5 -5
- seleniumbase/console_scripts/sb_install.py +235 -6
- seleniumbase/console_scripts/sb_mkdir.py +1 -0
- seleniumbase/core/browser_launcher.py +358 -105
- seleniumbase/core/log_helper.py +33 -12
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/sb_cdp.py +277 -74
- seleniumbase/core/settings_parser.py +2 -0
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/fixtures/base_case.py +216 -127
- seleniumbase/fixtures/constants.py +3 -0
- seleniumbase/fixtures/js_utils.py +2 -0
- seleniumbase/fixtures/page_actions.py +7 -2
- seleniumbase/fixtures/shared_utils.py +25 -0
- seleniumbase/plugins/driver_manager.py +28 -0
- seleniumbase/plugins/pytest_plugin.py +110 -0
- seleniumbase/plugins/sb_manager.py +41 -0
- seleniumbase/plugins/selenium_plugin.py +9 -0
- seleniumbase/undetected/cdp_driver/_contradict.py +3 -3
- seleniumbase/undetected/cdp_driver/browser.py +8 -6
- seleniumbase/undetected/cdp_driver/cdp_util.py +3 -0
- seleniumbase/undetected/cdp_driver/config.py +0 -1
- seleniumbase/undetected/cdp_driver/element.py +22 -20
- seleniumbase/undetected/patcher.py +20 -5
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/LICENSE +1 -1
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/METADATA +111 -86
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/RECORD +33 -33
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/WHEEL +1 -1
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.33.4.dist-info → seleniumbase-4.34.2.dist-info}/top_level.txt +0 -0
@@ -400,6 +400,7 @@ class ValidBinaries:
|
|
400
400
|
"google-chrome-beta",
|
401
401
|
"google-chrome-dev",
|
402
402
|
"google-chrome-unstable",
|
403
|
+
"chrome-headless-shell",
|
403
404
|
"brave-browser",
|
404
405
|
"brave-browser-stable",
|
405
406
|
"brave",
|
@@ -418,6 +419,7 @@ class ValidBinaries:
|
|
418
419
|
"Google Chrome",
|
419
420
|
"Chromium",
|
420
421
|
"Google Chrome for Testing",
|
422
|
+
"chrome-headless-shell",
|
421
423
|
"Google Chrome Beta",
|
422
424
|
"Google Chrome Dev",
|
423
425
|
"Brave Browser",
|
@@ -429,6 +431,7 @@ class ValidBinaries:
|
|
429
431
|
valid_chrome_binaries_on_windows = [
|
430
432
|
"chrome.exe",
|
431
433
|
"chromium.exe",
|
434
|
+
"chrome-headless-shell.exe",
|
432
435
|
"brave.exe",
|
433
436
|
"opera.exe",
|
434
437
|
]
|
@@ -1188,6 +1188,8 @@ def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur):
|
|
1188
1188
|
def get_active_element_css(driver):
|
1189
1189
|
from seleniumbase.js_code import active_css_js
|
1190
1190
|
|
1191
|
+
if shared_utils.is_cdp_swap_needed(driver):
|
1192
|
+
return driver.cdp.get_active_element_css()
|
1191
1193
|
return execute_script(driver, active_css_js.get_active_element_css)
|
1192
1194
|
|
1193
1195
|
|
@@ -1342,7 +1342,8 @@ def save_page_source(driver, name, folder=None):
|
|
1342
1342
|
"""
|
1343
1343
|
from seleniumbase.core import log_helper
|
1344
1344
|
|
1345
|
-
|
1345
|
+
if not __is_cdp_swap_needed(driver):
|
1346
|
+
_reconnect_if_disconnected(driver) # If disconnected without CDP
|
1346
1347
|
if not name.endswith(".html"):
|
1347
1348
|
name = name + ".html"
|
1348
1349
|
if folder:
|
@@ -1353,7 +1354,11 @@ def save_page_source(driver, name, folder=None):
|
|
1353
1354
|
html_file_path = os.path.join(file_path, name)
|
1354
1355
|
else:
|
1355
1356
|
html_file_path = name
|
1356
|
-
page_source =
|
1357
|
+
page_source = None
|
1358
|
+
if __is_cdp_swap_needed(driver):
|
1359
|
+
page_source = driver.cdp.get_page_source()
|
1360
|
+
else:
|
1361
|
+
page_source = driver.page_source
|
1357
1362
|
html_file = codecs.open(html_file_path, "w+", "utf-8")
|
1358
1363
|
rendered_source = log_helper.get_html_source_with_base_href(
|
1359
1364
|
driver, page_source
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Shared utility methods"""
|
2
2
|
import colorama
|
3
3
|
import os
|
4
|
+
import pathlib
|
4
5
|
import platform
|
5
6
|
import sys
|
6
7
|
import time
|
@@ -128,6 +129,30 @@ def is_chrome_130_or_newer(self, binary_location=None):
|
|
128
129
|
return False
|
129
130
|
|
130
131
|
|
132
|
+
def make_dir_files_writable(dir_path):
|
133
|
+
# Make all files in the given directory writable.
|
134
|
+
for file_path in pathlib.Path(dir_path).glob("*"):
|
135
|
+
if file_path.is_file():
|
136
|
+
mode = os.stat(file_path).st_mode
|
137
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
138
|
+
with suppress(Exception):
|
139
|
+
os.chmod(file_path, mode)
|
140
|
+
|
141
|
+
|
142
|
+
def make_writable(file_path):
|
143
|
+
# Set permissions to: "If you can read it, you can write it."
|
144
|
+
mode = os.stat(file_path).st_mode
|
145
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
146
|
+
os.chmod(file_path, mode)
|
147
|
+
|
148
|
+
|
149
|
+
def make_executable(file_path):
|
150
|
+
# Set permissions to: "If you can read it, you can execute it."
|
151
|
+
mode = os.stat(file_path).st_mode
|
152
|
+
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
153
|
+
os.chmod(file_path, mode)
|
154
|
+
|
155
|
+
|
131
156
|
def format_exc(exception, message):
|
132
157
|
"""Formats an exception message to make the output cleaner."""
|
133
158
|
from selenium.common.exceptions import ElementNotVisibleException
|
@@ -530,6 +530,34 @@ def Driver(
|
|
530
530
|
break
|
531
531
|
count += 1
|
532
532
|
user_agent = agent
|
533
|
+
found_bl = None
|
534
|
+
if binary_location is None and "--binary-location" in arg_join:
|
535
|
+
count = 0
|
536
|
+
for arg in sys_argv:
|
537
|
+
if arg.startswith("--binary-location="):
|
538
|
+
found_bl = arg.split("--binary-location=")[1]
|
539
|
+
break
|
540
|
+
elif arg == "--binary-location" and len(sys_argv) > count + 1:
|
541
|
+
found_bl = sys_argv[count + 1]
|
542
|
+
if found_bl.startswith("-"):
|
543
|
+
found_bl = None
|
544
|
+
break
|
545
|
+
count += 1
|
546
|
+
if found_bl:
|
547
|
+
binary_location = found_bl
|
548
|
+
if binary_location is None and "--bl=" in arg_join:
|
549
|
+
for arg in sys_argv:
|
550
|
+
if arg.startswith("--bl="):
|
551
|
+
binary_location = arg.split("--bl=")[1]
|
552
|
+
break
|
553
|
+
if (
|
554
|
+
binary_location
|
555
|
+
and binary_location.lower() == "chs"
|
556
|
+
and browser == "chrome"
|
557
|
+
):
|
558
|
+
headless = True
|
559
|
+
headless1 = False
|
560
|
+
headless2 = False
|
533
561
|
recorder_mode = False
|
534
562
|
if recorder_ext:
|
535
563
|
recorder_mode = True
|
@@ -656,6 +656,7 @@ def pytest_addoption(parser):
|
|
656
656
|
parser.addoption(
|
657
657
|
"--binary_location",
|
658
658
|
"--binary-location",
|
659
|
+
"--bl",
|
659
660
|
action="store",
|
660
661
|
dest="binary_location",
|
661
662
|
default=None,
|
@@ -1371,6 +1372,7 @@ def pytest_addoption(parser):
|
|
1371
1372
|
|
1372
1373
|
arg_join = " ".join(sys_argv)
|
1373
1374
|
sb_config._browser_shortcut = None
|
1375
|
+
sb_config._vd_list = []
|
1374
1376
|
|
1375
1377
|
# SeleniumBase does not support pytest-timeout due to hanging browsers.
|
1376
1378
|
for arg in sys_argv:
|
@@ -1573,6 +1575,14 @@ def pytest_configure(config):
|
|
1573
1575
|
sb_config.extension_dir = config.getoption("extension_dir")
|
1574
1576
|
sb_config.disable_features = config.getoption("disable_features")
|
1575
1577
|
sb_config.binary_location = config.getoption("binary_location")
|
1578
|
+
if (
|
1579
|
+
sb_config.binary_location
|
1580
|
+
and sb_config.binary_location.lower() == "chs"
|
1581
|
+
and sb_config.browser == "chrome"
|
1582
|
+
):
|
1583
|
+
sb_config.headless = True
|
1584
|
+
sb_config.headless1 = False
|
1585
|
+
sb_config.headless2 = False
|
1576
1586
|
sb_config.driver_version = config.getoption("driver_version")
|
1577
1587
|
sb_config.page_load_strategy = config.getoption("page_load_strategy")
|
1578
1588
|
sb_config.with_testing_base = config.getoption("with_testing_base")
|
@@ -1709,6 +1719,7 @@ def pytest_configure(config):
|
|
1709
1719
|
sb_config._saved_dashboard_pie = None # Copy of pie chart for html report
|
1710
1720
|
sb_config._dash_final_summary = None # Dash status to add to html report
|
1711
1721
|
sb_config._html_report_name = None # The name of the pytest html report
|
1722
|
+
sb_config._html_report_copy = None # The copy of the pytest html report
|
1712
1723
|
|
1713
1724
|
arg_join = " ".join(sys_argv)
|
1714
1725
|
if (
|
@@ -1742,6 +1753,7 @@ def pytest_configure(config):
|
|
1742
1753
|
if sb_config.dashboard:
|
1743
1754
|
if sb_config._html_report_name == "dashboard.html":
|
1744
1755
|
sb_config._dash_is_html_report = True
|
1756
|
+
sb_config._html_report_copy = "last_report.html"
|
1745
1757
|
|
1746
1758
|
# Recorder Mode does not support multi-threaded / multi-process runs.
|
1747
1759
|
if sb_config.recorder_mode and sb_config._multithreaded:
|
@@ -2015,6 +2027,13 @@ def pytest_runtest_teardown(item):
|
|
2015
2027
|
hasattr(self, "_xvfb_display")
|
2016
2028
|
and self._xvfb_display
|
2017
2029
|
and hasattr(self._xvfb_display, "stop")
|
2030
|
+
and (
|
2031
|
+
not hasattr(sb_config, "reuse_session")
|
2032
|
+
or (
|
2033
|
+
hasattr(sb_config, "reuse_session")
|
2034
|
+
and not sb_config.reuse_session
|
2035
|
+
)
|
2036
|
+
)
|
2018
2037
|
):
|
2019
2038
|
self.headless_active = False
|
2020
2039
|
sb_config.headless_active = False
|
@@ -2024,6 +2043,13 @@ def pytest_runtest_teardown(item):
|
|
2024
2043
|
hasattr(sb_config, "_virtual_display")
|
2025
2044
|
and sb_config._virtual_display
|
2026
2045
|
and hasattr(sb_config._virtual_display, "stop")
|
2046
|
+
and (
|
2047
|
+
not hasattr(sb_config, "reuse_session")
|
2048
|
+
or (
|
2049
|
+
hasattr(sb_config, "reuse_session")
|
2050
|
+
and not sb_config.reuse_session
|
2051
|
+
)
|
2052
|
+
)
|
2027
2053
|
):
|
2028
2054
|
sb_config._virtual_display.stop()
|
2029
2055
|
sb_config._virtual_display = None
|
@@ -2137,10 +2163,28 @@ def _perform_pytest_unconfigure_(config):
|
|
2137
2163
|
except Exception:
|
2138
2164
|
pass
|
2139
2165
|
sb_config.shared_driver = None
|
2166
|
+
with suppress(Exception):
|
2167
|
+
if (
|
2168
|
+
hasattr(sb_config, "_virtual_display")
|
2169
|
+
and sb_config._virtual_display
|
2170
|
+
and hasattr(sb_config._virtual_display, "stop")
|
2171
|
+
):
|
2172
|
+
sb_config._virtual_display.stop()
|
2173
|
+
sb_config._virtual_display = None
|
2174
|
+
sb_config.headless_active = False
|
2175
|
+
if hasattr(sb_config, "_vd_list") and sb_config._vd_list:
|
2176
|
+
if isinstance(sb_config._vd_list, list):
|
2177
|
+
for display in sb_config._vd_list:
|
2178
|
+
if display:
|
2179
|
+
with suppress(Exception):
|
2180
|
+
display.stop()
|
2140
2181
|
if hasattr(sb_config, "log_path") and sb_config.item_count > 0:
|
2141
2182
|
log_helper.archive_logs_if_set(
|
2142
2183
|
constants.Logs.LATEST + "/", sb_config.archive_logs
|
2143
2184
|
)
|
2185
|
+
if os.path.exists("./assets/"): # Used by pytest-html reports
|
2186
|
+
with suppress(Exception):
|
2187
|
+
shared_utils.make_dir_files_writable("./assets/")
|
2144
2188
|
log_helper.clear_empty_logs()
|
2145
2189
|
# Dashboard post-processing: Disable time-based refresh and stamp complete
|
2146
2190
|
if not hasattr(sb_config, "dashboard") or not sb_config.dashboard:
|
@@ -2151,6 +2195,10 @@ def _perform_pytest_unconfigure_(config):
|
|
2151
2195
|
html_report_path = os.path.join(
|
2152
2196
|
abs_path, sb_config._html_report_name
|
2153
2197
|
)
|
2198
|
+
if sb_config._html_report_copy:
|
2199
|
+
html_report_path_copy = os.path.join(
|
2200
|
+
abs_path, sb_config._html_report_copy
|
2201
|
+
)
|
2154
2202
|
if (
|
2155
2203
|
sb_config._using_html_report
|
2156
2204
|
and html_report_path
|
@@ -2184,6 +2232,9 @@ def _perform_pytest_unconfigure_(config):
|
|
2184
2232
|
the_html_r = the_html_r.replace(
|
2185
2233
|
ph_link, "%s and %s" % (sb_link, ph_link)
|
2186
2234
|
)
|
2235
|
+
the_html_r = the_html_r.replace(
|
2236
|
+
"findAll('.collapsible", "//findAll('.collapsible"
|
2237
|
+
)
|
2187
2238
|
the_html_r = the_html_r.replace(
|
2188
2239
|
"mediaName.innerText", "//mediaName.innerText"
|
2189
2240
|
)
|
@@ -2201,6 +2252,31 @@ def _perform_pytest_unconfigure_(config):
|
|
2201
2252
|
)
|
2202
2253
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2203
2254
|
f.write(the_html_r) # Finalize the HTML report
|
2255
|
+
with suppress(Exception):
|
2256
|
+
shared_utils.make_writable(html_report_path)
|
2257
|
+
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2258
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2259
|
+
with suppress(Exception):
|
2260
|
+
shared_utils.make_writable(html_report_path_copy)
|
2261
|
+
assets_style = "./assets/style.css"
|
2262
|
+
if os.path.exists(assets_style):
|
2263
|
+
html_style = None
|
2264
|
+
with open(assets_style, "r", encoding="utf-8") as f:
|
2265
|
+
html_style = f.read()
|
2266
|
+
if html_style:
|
2267
|
+
html_style = html_style.replace("top: -50px;", "top: 2px;")
|
2268
|
+
html_style = html_style.replace("+ 50px)", "+ 40px)")
|
2269
|
+
html_style = html_style.replace("ht: 240px;", "ht: 228px;")
|
2270
|
+
html_style = html_style.replace(
|
2271
|
+
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
2272
|
+
)
|
2273
|
+
html_style = html_style.replace(".collapsible", ".oldc")
|
2274
|
+
html_style = html_style.replace(" (hide details)", "")
|
2275
|
+
html_style = html_style.replace(" (show details)", "")
|
2276
|
+
with open(assets_style, "w", encoding="utf-8") as f:
|
2277
|
+
f.write(html_style)
|
2278
|
+
with suppress(Exception):
|
2279
|
+
shared_utils.make_writable(assets_style)
|
2204
2280
|
# Done with "pytest_unconfigure" unless using the Dashboard
|
2205
2281
|
return
|
2206
2282
|
stamp = ""
|
@@ -2282,12 +2358,37 @@ def _perform_pytest_unconfigure_(config):
|
|
2282
2358
|
)
|
2283
2359
|
with open(dashboard_path, "w", encoding="utf-8") as f:
|
2284
2360
|
f.write(the_html_d) # Finalize the dashboard
|
2361
|
+
with suppress(Exception):
|
2362
|
+
shared_utils.make_writable(dashboard_path)
|
2363
|
+
assets_style = "./assets/style.css"
|
2364
|
+
if os.path.exists(assets_style):
|
2365
|
+
html_style = None
|
2366
|
+
with open(assets_style, "r", encoding="utf-8") as f:
|
2367
|
+
html_style = f.read()
|
2368
|
+
if html_style:
|
2369
|
+
html_style = html_style.replace("top: -50px;", "top: 2px;")
|
2370
|
+
html_style = html_style.replace("+ 50px)", "+ 40px)")
|
2371
|
+
html_style = html_style.replace("ht: 240px;", "ht: 228px;")
|
2372
|
+
html_style = html_style.replace(
|
2373
|
+
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
2374
|
+
)
|
2375
|
+
html_style = html_style.replace(".collapsible", ".oldc")
|
2376
|
+
html_style = html_style.replace(" (hide details)", "")
|
2377
|
+
html_style = html_style.replace(" (show details)", "")
|
2378
|
+
with open(assets_style, "w", encoding="utf-8") as f:
|
2379
|
+
f.write(html_style)
|
2380
|
+
with suppress(Exception):
|
2381
|
+
shared_utils.make_writable(assets_style)
|
2285
2382
|
# Part 2: Appending a pytest html report with dashboard data
|
2286
2383
|
html_report_path = None
|
2287
2384
|
if sb_config._html_report_name:
|
2288
2385
|
html_report_path = os.path.join(
|
2289
2386
|
abs_path, sb_config._html_report_name
|
2290
2387
|
)
|
2388
|
+
if sb_config._html_report_copy:
|
2389
|
+
html_report_path_copy = os.path.join(
|
2390
|
+
abs_path, sb_config._html_report_copy
|
2391
|
+
)
|
2291
2392
|
if (
|
2292
2393
|
sb_config._using_html_report
|
2293
2394
|
and html_report_path
|
@@ -2341,6 +2442,9 @@ def _perform_pytest_unconfigure_(config):
|
|
2341
2442
|
the_html_r = the_html_r.replace(
|
2342
2443
|
ph_link, "%s and %s" % (sb_link, ph_link)
|
2343
2444
|
)
|
2445
|
+
the_html_r = the_html_r.replace(
|
2446
|
+
"findAll('.collapsible", "//findAll('.collapsible"
|
2447
|
+
)
|
2344
2448
|
the_html_r = the_html_r.replace(
|
2345
2449
|
"mediaName.innerText", "//mediaName.innerText"
|
2346
2450
|
)
|
@@ -2358,6 +2462,12 @@ def _perform_pytest_unconfigure_(config):
|
|
2358
2462
|
)
|
2359
2463
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2360
2464
|
f.write(the_html_r) # Finalize the HTML report
|
2465
|
+
with suppress(Exception):
|
2466
|
+
shared_utils.make_writable(html_report_path)
|
2467
|
+
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2468
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2469
|
+
with suppress(Exception):
|
2470
|
+
shared_utils.make_writable(html_report_path_copy)
|
2361
2471
|
except KeyboardInterrupt:
|
2362
2472
|
pass
|
2363
2473
|
except Exception:
|
@@ -568,6 +568,34 @@ def SB(
|
|
568
568
|
break
|
569
569
|
count += 1
|
570
570
|
user_agent = agent
|
571
|
+
found_bl = None
|
572
|
+
if binary_location is None and "--binary-location" in arg_join:
|
573
|
+
count = 0
|
574
|
+
for arg in sys_argv:
|
575
|
+
if arg.startswith("--binary-location="):
|
576
|
+
found_bl = arg.split("--binary-location=")[1]
|
577
|
+
break
|
578
|
+
elif arg == "--binary-location" and len(sys_argv) > count + 1:
|
579
|
+
found_bl = sys_argv[count + 1]
|
580
|
+
if found_bl.startswith("-"):
|
581
|
+
found_bl = None
|
582
|
+
break
|
583
|
+
count += 1
|
584
|
+
if found_bl:
|
585
|
+
binary_location = found_bl
|
586
|
+
if binary_location is None and "--bl=" in arg_join:
|
587
|
+
for arg in sys_argv:
|
588
|
+
if arg.startswith("--bl="):
|
589
|
+
binary_location = arg.split("--bl=")[1]
|
590
|
+
break
|
591
|
+
if (
|
592
|
+
binary_location
|
593
|
+
and binary_location.lower() == "chs"
|
594
|
+
and browser == "chrome"
|
595
|
+
):
|
596
|
+
headless = True
|
597
|
+
headless1 = False
|
598
|
+
headless2 = False
|
571
599
|
recorder_mode = False
|
572
600
|
if recorder_ext:
|
573
601
|
recorder_mode = True
|
@@ -1256,6 +1284,19 @@ def SB(
|
|
1256
1284
|
print(traceback.format_exc().strip())
|
1257
1285
|
if test and not test_passed:
|
1258
1286
|
print("********** ERROR: The test AND the tearDown() FAILED!")
|
1287
|
+
if (
|
1288
|
+
hasattr(sb_config, "_virtual_display")
|
1289
|
+
and sb_config._virtual_display
|
1290
|
+
and hasattr(sb_config._virtual_display, "stop")
|
1291
|
+
):
|
1292
|
+
try:
|
1293
|
+
sb_config._virtual_display.stop()
|
1294
|
+
sb_config._virtual_display = None
|
1295
|
+
sb_config.headless_active = False
|
1296
|
+
except AttributeError:
|
1297
|
+
pass
|
1298
|
+
except Exception:
|
1299
|
+
pass
|
1259
1300
|
end_time = time.time()
|
1260
1301
|
run_time = end_time - start_time
|
1261
1302
|
sb_config = sb_config_backup
|
@@ -397,6 +397,7 @@ class SeleniumBrowser(Plugin):
|
|
397
397
|
parser.addoption(
|
398
398
|
"--binary_location",
|
399
399
|
"--binary-location",
|
400
|
+
"--bl",
|
400
401
|
action="store",
|
401
402
|
dest="binary_location",
|
402
403
|
default=None,
|
@@ -1202,6 +1203,14 @@ class SeleniumBrowser(Plugin):
|
|
1202
1203
|
test.test.extension_dir = self.options.extension_dir
|
1203
1204
|
test.test.disable_features = self.options.disable_features
|
1204
1205
|
test.test.binary_location = self.options.binary_location
|
1206
|
+
if (
|
1207
|
+
test.test.binary_location
|
1208
|
+
and test.test.binary_location.lower() == "chs"
|
1209
|
+
and test.test.browser == "chrome"
|
1210
|
+
):
|
1211
|
+
test.test.headless = True
|
1212
|
+
test.test.headless1 = False
|
1213
|
+
test.test.headless2 = False
|
1205
1214
|
test.test.driver_version = self.options.driver_version
|
1206
1215
|
test.test.page_load_strategy = self.options.page_load_strategy
|
1207
1216
|
test.test.chromium_arg = self.options.chromium_arg
|
@@ -31,12 +31,12 @@ class ContraDict(dict):
|
|
31
31
|
|
32
32
|
def __init__(self, *args, **kwargs):
|
33
33
|
super().__init__()
|
34
|
-
silent = kwargs.pop("silent", False)
|
34
|
+
# silent = kwargs.pop("silent", False)
|
35
35
|
_ = dict(*args, **kwargs)
|
36
36
|
|
37
37
|
super().__setattr__("__dict__", self)
|
38
38
|
for k, v in _.items():
|
39
|
-
_check_key(k, self, False,
|
39
|
+
_check_key(k, self, False, True)
|
40
40
|
super().__setitem__(k, _wrap(self.__class__, v))
|
41
41
|
|
42
42
|
def __setitem__(self, key, value):
|
@@ -90,7 +90,7 @@ _warning_names_message = """\n\
|
|
90
90
|
|
91
91
|
|
92
92
|
def _check_key(
|
93
|
-
key: str, mapping: _Mapping, boolean: bool = False, silent=
|
93
|
+
key: str, mapping: _Mapping, boolean: bool = False, silent=True
|
94
94
|
):
|
95
95
|
"""Checks `key` and warns if needed.
|
96
96
|
:param key:
|
@@ -10,6 +10,7 @@ import pathlib
|
|
10
10
|
import pickle
|
11
11
|
import re
|
12
12
|
import shutil
|
13
|
+
import time
|
13
14
|
import urllib.parse
|
14
15
|
import urllib.request
|
15
16
|
import warnings
|
@@ -30,8 +31,6 @@ def get_registered_instances():
|
|
30
31
|
|
31
32
|
|
32
33
|
def deconstruct_browser():
|
33
|
-
import time
|
34
|
-
|
35
34
|
for _ in __registered__instances__:
|
36
35
|
if not _.stopped:
|
37
36
|
_.stop()
|
@@ -117,8 +116,13 @@ class Browser:
|
|
117
116
|
port=port,
|
118
117
|
**kwargs,
|
119
118
|
)
|
120
|
-
|
121
|
-
|
119
|
+
try:
|
120
|
+
instance = cls(config)
|
121
|
+
await instance.start()
|
122
|
+
except Exception:
|
123
|
+
time.sleep(0.15)
|
124
|
+
instance = cls(config)
|
125
|
+
await instance.start()
|
122
126
|
return instance
|
123
127
|
|
124
128
|
def __init__(self, config: Config, **kwargs):
|
@@ -379,8 +383,6 @@ class Browser:
|
|
379
383
|
--------------------------------
|
380
384
|
Failed to connect to the browser
|
381
385
|
--------------------------------
|
382
|
-
Possibly because you are running as "root".
|
383
|
-
If so, you may need to use no_sandbox=True.
|
384
386
|
"""
|
385
387
|
)
|
386
388
|
)
|
@@ -84,6 +84,9 @@ def __activate_virtual_display_as_needed(
|
|
84
84
|
"\nX11 display failed! Will use regular xvfb!"
|
85
85
|
)
|
86
86
|
__activate_standard_virtual_display()
|
87
|
+
else:
|
88
|
+
sb_config._virtual_display = _xvfb_display
|
89
|
+
sb_config.headless_active = True
|
87
90
|
except Exception as e:
|
88
91
|
if hasattr(e, "msg"):
|
89
92
|
print("\n" + str(e.msg))
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
import asyncio
|
3
|
-
import json
|
4
3
|
import logging
|
5
4
|
import pathlib
|
6
5
|
import secrets
|
@@ -387,18 +386,16 @@ class Element:
|
|
387
386
|
|
388
387
|
async def get_js_attributes_async(self):
|
389
388
|
return ContraDict(
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
389
|
+
await self.apply(
|
390
|
+
"""
|
391
|
+
function (e) {
|
392
|
+
let o = {}
|
393
|
+
for(let k in e){
|
394
|
+
o[k] = e[k]
|
395
|
+
}
|
396
|
+
return o
|
397
397
|
}
|
398
|
-
|
399
|
-
}
|
400
|
-
"""
|
401
|
-
)
|
398
|
+
"""
|
402
399
|
)
|
403
400
|
)
|
404
401
|
|
@@ -441,12 +438,15 @@ class Element:
|
|
441
438
|
)
|
442
439
|
)
|
443
440
|
)
|
444
|
-
|
445
|
-
if
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
441
|
+
try:
|
442
|
+
if result and result[0]:
|
443
|
+
if return_by_value:
|
444
|
+
return result[0].value
|
445
|
+
return result[0]
|
446
|
+
elif result[1]:
|
447
|
+
return result[1]
|
448
|
+
except Exception:
|
449
|
+
return self
|
450
450
|
|
451
451
|
async def get_position_async(self, abs=False) -> Position:
|
452
452
|
if not self.parent or not self.object_id:
|
@@ -883,6 +883,8 @@ class Element:
|
|
883
883
|
self,
|
884
884
|
duration: typing.Union[float, int] = 0.5,
|
885
885
|
color: typing.Optional[str] = "EE4488",
|
886
|
+
x_offset: typing.Union[float, int] = 0,
|
887
|
+
y_offset: typing.Union[float, int] = 0,
|
886
888
|
):
|
887
889
|
"""
|
888
890
|
Displays for a short time a red dot on the element.
|
@@ -910,8 +912,8 @@ class Element:
|
|
910
912
|
"width:8px;height:8px;border-radius:50%;background:#{};"
|
911
913
|
"animation:show-pointer-ani {:.2f}s ease 1;"
|
912
914
|
).format(
|
913
|
-
pos.center[0] - 4, # -4 to account for
|
914
|
-
pos.center[1] - 4,
|
915
|
+
pos.center[0] + x_offset - 4, # -4 to account for the circle
|
916
|
+
pos.center[1] + y_offset - 4, # -4 to account for the circle
|
915
917
|
color,
|
916
918
|
duration,
|
917
919
|
)
|
@@ -8,6 +8,8 @@ import sys
|
|
8
8
|
import time
|
9
9
|
import zipfile
|
10
10
|
from contextlib import suppress
|
11
|
+
from seleniumbase.console_scripts import sb_install
|
12
|
+
from seleniumbase.fixtures import shared_utils
|
11
13
|
|
12
14
|
logger = logging.getLogger(__name__)
|
13
15
|
IS_POSIX = sys.platform.startswith(("darwin", "cygwin", "linux"))
|
@@ -106,7 +108,14 @@ class Patcher(object):
|
|
106
108
|
release = self.fetch_release_number()
|
107
109
|
self.version_main = release.split(".")[0]
|
108
110
|
self.version_full = release
|
109
|
-
|
111
|
+
if int(self.version_main) < 115:
|
112
|
+
self.unzip_package(self.fetch_package())
|
113
|
+
else:
|
114
|
+
sb_install.main(
|
115
|
+
override="chromedriver %s" % self.version_main,
|
116
|
+
intel_for_uc=shared_utils.is_arm_mac(),
|
117
|
+
force_uc=True,
|
118
|
+
)
|
110
119
|
return self.patch()
|
111
120
|
|
112
121
|
def patch(self):
|
@@ -121,6 +130,12 @@ class Patcher(object):
|
|
121
130
|
path += "_%s" % self.version_main
|
122
131
|
path = path.upper()
|
123
132
|
logger.debug("Getting release number from %s" % path)
|
133
|
+
if self.version_main and int(self.version_main) > 114:
|
134
|
+
return (
|
135
|
+
sb_install.get_cft_latest_version_from_milestone(
|
136
|
+
str(self.version_main)
|
137
|
+
)
|
138
|
+
)
|
124
139
|
return urlopen(self.url_repo + path).read().decode()
|
125
140
|
|
126
141
|
def fetch_package(self):
|
@@ -187,7 +202,7 @@ class Patcher(object):
|
|
187
202
|
with io.open(executable_path, "rb") as fh:
|
188
203
|
if re.search(
|
189
204
|
b"window.cdc_adoQpoasnfa76pfcZLmcfl_"
|
190
|
-
b"(Array|Promise|Symbol|Object|Proxy|JSON)",
|
205
|
+
b"(Array|Promise|Symbol|Object|Proxy|JSON|Window)",
|
191
206
|
fh.read()
|
192
207
|
):
|
193
208
|
return False
|
@@ -210,14 +225,14 @@ class Patcher(object):
|
|
210
225
|
file_bin = fh.read()
|
211
226
|
file_bin = re.sub(
|
212
227
|
b"window\\.cdc_[a-zA-Z0-9]{22}_"
|
213
|
-
b"(Array|Promise|Symbol|Object|Proxy|JSON)"
|
214
|
-
b"
|
228
|
+
b"(Array|Promise|Symbol|Object|Proxy|JSON|Window) "
|
229
|
+
b"= window\\.(Array|Promise|Symbol|Object|Proxy|JSON|Window);",
|
215
230
|
gen_js_whitespaces,
|
216
231
|
file_bin,
|
217
232
|
)
|
218
233
|
file_bin = re.sub(
|
219
234
|
b"window\\.cdc_[a-zA-Z0-9]{22}_"
|
220
|
-
b"(Array|Promise|Symbol|Object|Proxy|JSON) \\|\\|",
|
235
|
+
b"(Array|Promise|Symbol|Object|Proxy|JSON|Window) \\|\\|",
|
221
236
|
gen_js_whitespaces,
|
222
237
|
file_bin,
|
223
238
|
)
|