seleniumbase 4.33.6__py3-none-any.whl → 4.33.8__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- seleniumbase/__version__.py +1 -1
- seleniumbase/core/browser_launcher.py +48 -29
- seleniumbase/core/log_helper.py +10 -4
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/sb_cdp.py +82 -24
- seleniumbase/core/settings_parser.py +2 -0
- seleniumbase/fixtures/base_case.py +36 -37
- seleniumbase/fixtures/js_utils.py +2 -0
- seleniumbase/fixtures/shared_utils.py +11 -0
- seleniumbase/plugins/pytest_plugin.py +19 -2
- seleniumbase/undetected/cdp_driver/config.py +0 -1
- seleniumbase/undetected/cdp_driver/element.py +13 -14
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/METADATA +1 -1
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/RECORD +18 -18
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/LICENSE +0 -0
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/WHEEL +0 -0
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.33.6.dist-info → seleniumbase-4.33.8.dist-info}/top_level.txt +0 -0
seleniumbase/__version__.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
# seleniumbase package
|
2
|
-
__version__ = "4.33.
|
2
|
+
__version__ = "4.33.8"
|
@@ -658,6 +658,7 @@ def uc_open_with_cdp_mode(driver, url=None):
|
|
658
658
|
cdp.get_window = CDPM.get_window
|
659
659
|
cdp.get_element_attributes = CDPM.get_element_attributes
|
660
660
|
cdp.get_element_attribute = CDPM.get_element_attribute
|
661
|
+
cdp.get_attribute = CDPM.get_attribute
|
661
662
|
cdp.get_element_html = CDPM.get_element_html
|
662
663
|
cdp.get_element_rect = CDPM.get_element_rect
|
663
664
|
cdp.get_element_size = CDPM.get_element_size
|
@@ -1413,7 +1414,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1413
1414
|
ctype = "cf_t"
|
1414
1415
|
else:
|
1415
1416
|
return
|
1416
|
-
if not driver.is_connected():
|
1417
|
+
if not driver.is_connected() and not __is_cdp_swap_needed(driver):
|
1417
1418
|
driver.connect()
|
1418
1419
|
time.sleep(2)
|
1419
1420
|
install_pyautogui_if_missing(driver)
|
@@ -1425,7 +1426,10 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1425
1426
|
)
|
1426
1427
|
with gui_lock: # Prevent issues with multiple processes
|
1427
1428
|
needs_switch = False
|
1428
|
-
|
1429
|
+
if not __is_cdp_swap_needed(driver):
|
1430
|
+
is_in_frame = js_utils.is_in_frame(driver)
|
1431
|
+
else:
|
1432
|
+
is_in_frame = False
|
1429
1433
|
selector = "#challenge-stage"
|
1430
1434
|
if ctype == "g_rc":
|
1431
1435
|
selector = "#recaptcha-token"
|
@@ -1433,7 +1437,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1433
1437
|
driver.switch_to.parent_frame()
|
1434
1438
|
needs_switch = True
|
1435
1439
|
is_in_frame = js_utils.is_in_frame(driver)
|
1436
|
-
if not is_in_frame:
|
1440
|
+
if not is_in_frame and not __is_cdp_swap_needed(driver):
|
1437
1441
|
# Make sure the window is on top
|
1438
1442
|
page_actions.switch_to_window(
|
1439
1443
|
driver, driver.current_window_handle, 2, uc_lock=False
|
@@ -1500,17 +1504,18 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1500
1504
|
and frame == "iframe"
|
1501
1505
|
):
|
1502
1506
|
frame = 'iframe[title="reCAPTCHA"]'
|
1503
|
-
if not
|
1504
|
-
|
1505
|
-
|
1506
|
-
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
if
|
1511
|
-
driver.
|
1512
|
-
|
1513
|
-
|
1507
|
+
if not __is_cdp_swap_needed(driver):
|
1508
|
+
if not is_in_frame or needs_switch:
|
1509
|
+
# Currently not in frame (or nested frame outside CF one)
|
1510
|
+
try:
|
1511
|
+
if visible_iframe or ctype == "g_rc":
|
1512
|
+
driver.switch_to_frame(frame)
|
1513
|
+
except Exception:
|
1514
|
+
if visible_iframe or ctype == "g_rc":
|
1515
|
+
if driver.is_element_present("iframe"):
|
1516
|
+
driver.switch_to_frame("iframe")
|
1517
|
+
else:
|
1518
|
+
return
|
1514
1519
|
try:
|
1515
1520
|
selector = "div.cf-turnstile"
|
1516
1521
|
if ctype == "g_rc":
|
@@ -1526,11 +1531,11 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1526
1531
|
tab_count += 1
|
1527
1532
|
time.sleep(0.027)
|
1528
1533
|
active_element_css = js_utils.get_active_element_css(driver)
|
1529
|
-
print(active_element_css)
|
1530
1534
|
if (
|
1531
1535
|
active_element_css.startswith(selector)
|
1532
1536
|
or active_element_css.endswith(" > div" * 2)
|
1533
1537
|
or (special_form and active_element_css.endswith(" div"))
|
1538
|
+
or (ctype == "g_rc" and "frame[name" in active_element_css)
|
1534
1539
|
):
|
1535
1540
|
found_checkbox = True
|
1536
1541
|
sb_config._saved_cf_tab_count = tab_count
|
@@ -1550,6 +1555,7 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None):
|
|
1550
1555
|
)
|
1551
1556
|
and hasattr(sb_config, "_saved_cf_tab_count")
|
1552
1557
|
and sb_config._saved_cf_tab_count
|
1558
|
+
and not __is_cdp_swap_needed(driver)
|
1553
1559
|
):
|
1554
1560
|
driver.uc_open_with_disconnect(driver.current_url, 3.8)
|
1555
1561
|
with suppress(Exception):
|
@@ -1764,17 +1770,27 @@ def _add_chrome_proxy_extension(
|
|
1764
1770
|
):
|
1765
1771
|
# Single-threaded
|
1766
1772
|
if zip_it:
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1773
|
+
proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
|
1774
|
+
with proxy_zip_lock:
|
1775
|
+
proxy_helper.create_proxy_ext(
|
1776
|
+
proxy_string, proxy_user, proxy_pass, bypass_list
|
1777
|
+
)
|
1778
|
+
proxy_zip = proxy_helper.PROXY_ZIP_PATH
|
1779
|
+
chrome_options.add_extension(proxy_zip)
|
1772
1780
|
else:
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1781
|
+
proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
|
1782
|
+
with proxy_dir_lock:
|
1783
|
+
proxy_helper.create_proxy_ext(
|
1784
|
+
proxy_string,
|
1785
|
+
proxy_user,
|
1786
|
+
proxy_pass,
|
1787
|
+
bypass_list,
|
1788
|
+
zip_it=False,
|
1789
|
+
)
|
1790
|
+
proxy_dir_path = proxy_helper.PROXY_DIR_PATH
|
1791
|
+
chrome_options = add_chrome_ext_dir(
|
1792
|
+
chrome_options, proxy_dir_path
|
1793
|
+
)
|
1778
1794
|
else:
|
1779
1795
|
# Multi-threaded
|
1780
1796
|
if zip_it:
|
@@ -1803,7 +1819,7 @@ def _add_chrome_proxy_extension(
|
|
1803
1819
|
proxy_user,
|
1804
1820
|
proxy_pass,
|
1805
1821
|
bypass_list,
|
1806
|
-
False,
|
1822
|
+
zip_it=False,
|
1807
1823
|
)
|
1808
1824
|
chrome_options = add_chrome_ext_dir(
|
1809
1825
|
chrome_options, proxy_helper.PROXY_DIR_PATH
|
@@ -2306,7 +2322,6 @@ def _set_chrome_options(
|
|
2306
2322
|
chrome_options.add_argument("--disable-ipc-flooding-protection")
|
2307
2323
|
chrome_options.add_argument("--disable-password-generation")
|
2308
2324
|
chrome_options.add_argument("--disable-domain-reliability")
|
2309
|
-
chrome_options.add_argument("--disable-component-update")
|
2310
2325
|
chrome_options.add_argument("--disable-breakpad")
|
2311
2326
|
included_disabled_features = []
|
2312
2327
|
included_disabled_features.append("OptimizationHints")
|
@@ -4056,7 +4071,6 @@ def get_local_driver(
|
|
4056
4071
|
edge_options.add_argument("--disable-ipc-flooding-protection")
|
4057
4072
|
edge_options.add_argument("--disable-password-generation")
|
4058
4073
|
edge_options.add_argument("--disable-domain-reliability")
|
4059
|
-
edge_options.add_argument("--disable-component-update")
|
4060
4074
|
edge_options.add_argument("--disable-breakpad")
|
4061
4075
|
included_disabled_features = []
|
4062
4076
|
included_disabled_features.append("OptimizationHints")
|
@@ -4845,7 +4859,12 @@ def get_local_driver(
|
|
4845
4859
|
)
|
4846
4860
|
uc_activated = True
|
4847
4861
|
except URLError as e:
|
4848
|
-
if
|
4862
|
+
if (
|
4863
|
+
IS_MAC
|
4864
|
+
and hasattr(e, "args")
|
4865
|
+
and isinstance(e.args, (list, tuple))
|
4866
|
+
and cert in e.args[0]
|
4867
|
+
):
|
4849
4868
|
mac_certificate_error = True
|
4850
4869
|
else:
|
4851
4870
|
raise
|
seleniumbase/core/log_helper.py
CHANGED
@@ -7,6 +7,7 @@ from contextlib import suppress
|
|
7
7
|
from seleniumbase import config as sb_config
|
8
8
|
from seleniumbase.config import settings
|
9
9
|
from seleniumbase.fixtures import constants
|
10
|
+
from seleniumbase.fixtures import shared_utils
|
10
11
|
|
11
12
|
python3_11_or_newer = False
|
12
13
|
if sys.version_info >= (3, 11):
|
@@ -33,6 +34,8 @@ def log_screenshot(test_logpath, driver, screenshot=None, get=False):
|
|
33
34
|
if screenshot != screenshot_warning:
|
34
35
|
with open(screenshot_path, "wb") as file:
|
35
36
|
file.write(screenshot)
|
37
|
+
with suppress(Exception):
|
38
|
+
shared_utils.make_writable(screenshot_path)
|
36
39
|
else:
|
37
40
|
print("WARNING: %s" % screenshot_warning)
|
38
41
|
if get:
|
@@ -282,13 +285,14 @@ def log_test_failure_data(test, test_logpath, driver, browser, url=None):
|
|
282
285
|
sb_config._report_time = the_time
|
283
286
|
sb_config._report_traceback = traceback_message
|
284
287
|
sb_config._report_exception = exc_message
|
285
|
-
|
286
|
-
|
288
|
+
if not os.path.exists(test_logpath):
|
289
|
+
with suppress(Exception):
|
287
290
|
os.makedirs(test_logpath)
|
288
291
|
with suppress(Exception):
|
289
292
|
log_file = codecs.open(basic_file_path, "w+", encoding="utf-8")
|
290
293
|
log_file.writelines("\r\n".join(data_to_save))
|
291
294
|
log_file.close()
|
295
|
+
shared_utils.make_writable(basic_file_path)
|
292
296
|
|
293
297
|
|
294
298
|
def log_skipped_test_data(test, test_logpath, driver, browser, reason):
|
@@ -343,6 +347,7 @@ def log_skipped_test_data(test, test_logpath, driver, browser, reason):
|
|
343
347
|
log_file = codecs.open(file_path, "w+", encoding="utf-8")
|
344
348
|
log_file.writelines("\r\n".join(data_to_save))
|
345
349
|
log_file.close()
|
350
|
+
shared_utils.make_writable(file_path)
|
346
351
|
|
347
352
|
|
348
353
|
def log_page_source(test_logpath, driver, source=None):
|
@@ -365,14 +370,15 @@ def log_page_source(test_logpath, driver, source=None):
|
|
365
370
|
"unresponsive, or closed prematurely!</h4>"
|
366
371
|
)
|
367
372
|
)
|
368
|
-
|
369
|
-
|
373
|
+
if not os.path.exists(test_logpath):
|
374
|
+
with suppress(Exception):
|
370
375
|
os.makedirs(test_logpath)
|
371
376
|
html_file_path = os.path.join(test_logpath, html_file_name)
|
372
377
|
with suppress(Exception):
|
373
378
|
html_file = codecs.open(html_file_path, "w+", encoding="utf-8")
|
374
379
|
html_file.write(page_source)
|
375
380
|
html_file.close()
|
381
|
+
shared_utils.make_writable(html_file_path)
|
376
382
|
|
377
383
|
|
378
384
|
def get_test_id(test):
|
@@ -2,10 +2,12 @@ import os
|
|
2
2
|
import re
|
3
3
|
import warnings
|
4
4
|
import zipfile
|
5
|
+
from contextlib import suppress
|
5
6
|
from seleniumbase.config import proxy_list
|
6
7
|
from seleniumbase.config import settings
|
7
8
|
from seleniumbase.fixtures import constants
|
8
9
|
from seleniumbase.fixtures import page_utils
|
10
|
+
from seleniumbase.fixtures import shared_utils
|
9
11
|
|
10
12
|
DOWNLOADS_DIR = constants.Files.DOWNLOADS_FOLDER
|
11
13
|
PROXY_ZIP_PATH = os.path.join(DOWNLOADS_DIR, "proxy.zip")
|
@@ -109,31 +111,35 @@ def create_proxy_ext(
|
|
109
111
|
""""minimum_chrome_version":"22.0.0"\n"""
|
110
112
|
"""}"""
|
111
113
|
)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
proxy_ext_dir
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
114
|
+
abs_path = os.path.abspath(".")
|
115
|
+
downloads_path = os.path.join(abs_path, DOWNLOADS_DIR)
|
116
|
+
if not os.path.exists(downloads_path):
|
117
|
+
os.mkdir(downloads_path)
|
118
|
+
if zip_it:
|
119
|
+
zf = zipfile.ZipFile(PROXY_ZIP_PATH, mode="w")
|
120
|
+
zf.writestr("background.js", background_js)
|
121
|
+
zf.writestr("manifest.json", manifest_json)
|
122
|
+
zf.close()
|
123
|
+
with suppress(Exception):
|
124
|
+
shared_utils.make_writable(PROXY_ZIP_PATH)
|
125
|
+
else:
|
126
|
+
proxy_ext_dir = PROXY_DIR_PATH
|
127
|
+
if not os.path.exists(proxy_ext_dir):
|
128
|
+
os.mkdir(proxy_ext_dir)
|
129
|
+
with suppress(Exception):
|
130
|
+
shared_utils.make_writable(proxy_ext_dir)
|
131
|
+
manifest_file = os.path.join(proxy_ext_dir, "manifest.json")
|
132
|
+
with open(manifest_file, mode="w") as f:
|
133
|
+
f.write(manifest_json)
|
134
|
+
with suppress(Exception):
|
135
|
+
shared_utils.make_writable(manifest_json)
|
136
|
+
proxy_host = proxy_string.split(":")[0]
|
137
|
+
proxy_port = proxy_string.split(":")[1]
|
138
|
+
background_file = os.path.join(proxy_ext_dir, "background.js")
|
139
|
+
with open(background_file, mode="w") as f:
|
140
|
+
f.write(background_js)
|
141
|
+
with suppress(Exception):
|
142
|
+
shared_utils.make_writable(background_js)
|
137
143
|
|
138
144
|
|
139
145
|
def remove_proxy_zip_if_present():
|
@@ -141,13 +147,12 @@ def remove_proxy_zip_if_present():
|
|
141
147
|
Used in the implementation of https://stackoverflow.com/a/35293284
|
142
148
|
for https://stackoverflow.com/questions/12848327/
|
143
149
|
"""
|
144
|
-
|
145
|
-
|
150
|
+
if os.path.exists(PROXY_ZIP_PATH):
|
151
|
+
with suppress(Exception):
|
146
152
|
os.remove(PROXY_ZIP_PATH)
|
147
|
-
|
153
|
+
if os.path.exists(PROXY_ZIP_LOCK):
|
154
|
+
with suppress(Exception):
|
148
155
|
os.remove(PROXY_ZIP_LOCK)
|
149
|
-
except Exception:
|
150
|
-
pass
|
151
156
|
|
152
157
|
|
153
158
|
def validate_proxy_string(proxy_string):
|
seleniumbase/core/sb_cdp.py
CHANGED
@@ -83,6 +83,9 @@ class CDPMethods():
|
|
83
83
|
element.get_position = lambda: self.__get_position(element)
|
84
84
|
element.get_html = lambda: self.__get_html(element)
|
85
85
|
element.get_js_attributes = lambda: self.__get_js_attributes(element)
|
86
|
+
element.get_attribute = (
|
87
|
+
lambda attribute: self.__get_attribute(element, attribute)
|
88
|
+
)
|
86
89
|
return element
|
87
90
|
|
88
91
|
def get(self, url):
|
@@ -268,6 +271,7 @@ class CDPMethods():
|
|
268
271
|
if number < 0:
|
269
272
|
number = 0
|
270
273
|
element = elements[number]
|
274
|
+
element.scroll_into_view()
|
271
275
|
element.click()
|
272
276
|
|
273
277
|
def click_nth_visible_element(self, selector, number):
|
@@ -284,6 +288,7 @@ class CDPMethods():
|
|
284
288
|
if number < 0:
|
285
289
|
number = 0
|
286
290
|
element = elements[number]
|
291
|
+
element.scroll_into_view()
|
287
292
|
element.click()
|
288
293
|
|
289
294
|
def click_link(self, link_text):
|
@@ -311,6 +316,13 @@ class CDPMethods():
|
|
311
316
|
return result
|
312
317
|
|
313
318
|
def __flash(self, element, *args, **kwargs):
|
319
|
+
element.scroll_into_view()
|
320
|
+
if len(args) < 3 and "x_offset" not in kwargs:
|
321
|
+
x_offset = self.__get_x_scroll_offset()
|
322
|
+
kwargs["x_offset"] = x_offset
|
323
|
+
if len(args) < 3 and "y_offset" not in kwargs:
|
324
|
+
y_offset = self.__get_y_scroll_offset()
|
325
|
+
kwargs["y_offset"] = y_offset
|
314
326
|
return (
|
315
327
|
self.loop.run_until_complete(
|
316
328
|
element.flash_async(*args, **kwargs)
|
@@ -382,9 +394,9 @@ class CDPMethods():
|
|
382
394
|
)
|
383
395
|
|
384
396
|
def __scroll_into_view(self, element):
|
385
|
-
|
386
|
-
|
387
|
-
|
397
|
+
self.loop.run_until_complete(element.scroll_into_view_async())
|
398
|
+
self.__add_light_pause()
|
399
|
+
return None
|
388
400
|
|
389
401
|
def __select_option(self, element):
|
390
402
|
return (
|
@@ -431,6 +443,24 @@ class CDPMethods():
|
|
431
443
|
self.loop.run_until_complete(element.get_js_attributes_async())
|
432
444
|
)
|
433
445
|
|
446
|
+
def __get_attribute(self, element, attribute):
|
447
|
+
try:
|
448
|
+
return element.get_js_attributes()[attribute]
|
449
|
+
except Exception:
|
450
|
+
return None
|
451
|
+
|
452
|
+
def __get_x_scroll_offset(self):
|
453
|
+
x_scroll_offset = self.loop.run_until_complete(
|
454
|
+
self.page.evaluate("window.pageXOffset")
|
455
|
+
)
|
456
|
+
return x_scroll_offset or 0
|
457
|
+
|
458
|
+
def __get_y_scroll_offset(self):
|
459
|
+
y_scroll_offset = self.loop.run_until_complete(
|
460
|
+
self.page.evaluate("window.pageYOffset")
|
461
|
+
)
|
462
|
+
return y_scroll_offset or 0
|
463
|
+
|
434
464
|
def tile_windows(self, windows=None, max_columns=0):
|
435
465
|
"""Tile windows and return the grid of tiled windows."""
|
436
466
|
driver = self.driver
|
@@ -504,7 +534,7 @@ class CDPMethods():
|
|
504
534
|
def click(self, selector, timeout=settings.SMALL_TIMEOUT):
|
505
535
|
self.__slow_mode_pause_if_set()
|
506
536
|
element = self.find_element(selector, timeout=timeout)
|
507
|
-
|
537
|
+
element.scroll_into_view()
|
508
538
|
element.click()
|
509
539
|
self.__slow_mode_pause_if_set()
|
510
540
|
self.loop.run_until_complete(self.page.wait())
|
@@ -518,7 +548,9 @@ class CDPMethods():
|
|
518
548
|
|
519
549
|
def click_if_visible(self, selector):
|
520
550
|
if self.is_element_visible(selector):
|
521
|
-
self.find_element(selector)
|
551
|
+
element = self.find_element(selector)
|
552
|
+
element.scroll_into_view()
|
553
|
+
element.click()
|
522
554
|
self.__slow_mode_pause_if_set()
|
523
555
|
self.loop.run_until_complete(self.page.wait())
|
524
556
|
|
@@ -545,9 +577,10 @@ class CDPMethods():
|
|
545
577
|
except Exception:
|
546
578
|
continue
|
547
579
|
if (width != 0 or height != 0):
|
580
|
+
element.scroll_into_view()
|
548
581
|
element.click()
|
549
582
|
click_count += 1
|
550
|
-
time.sleep(0.
|
583
|
+
time.sleep(0.042)
|
551
584
|
self.__slow_mode_pause_if_set()
|
552
585
|
self.loop.run_until_complete(self.page.wait())
|
553
586
|
except Exception:
|
@@ -557,7 +590,7 @@ class CDPMethods():
|
|
557
590
|
"""(Attempt simulating a mouse click)"""
|
558
591
|
self.__slow_mode_pause_if_set()
|
559
592
|
element = self.find_element(selector, timeout=timeout)
|
560
|
-
|
593
|
+
element.scroll_into_view()
|
561
594
|
element.mouse_click()
|
562
595
|
self.__slow_mode_pause_if_set()
|
563
596
|
self.loop.run_until_complete(self.page.wait())
|
@@ -579,6 +612,7 @@ class CDPMethods():
|
|
579
612
|
|
580
613
|
def select_option_by_text(self, dropdown_selector, option):
|
581
614
|
element = self.find_element(dropdown_selector)
|
615
|
+
element.scroll_into_view()
|
582
616
|
options = element.query_selector_all("option")
|
583
617
|
for found_option in options:
|
584
618
|
if found_option.text.strip() == option.strip():
|
@@ -599,7 +633,10 @@ class CDPMethods():
|
|
599
633
|
"""Paint a quickly-vanishing dot over an element."""
|
600
634
|
selector = self.__convert_to_css_if_xpath(selector)
|
601
635
|
element = self.find_element(selector)
|
602
|
-
element.
|
636
|
+
element.scroll_into_view()
|
637
|
+
x_offset = self.__get_x_scroll_offset()
|
638
|
+
y_offset = self.__get_y_scroll_offset()
|
639
|
+
element.flash(duration, color, x_offset, y_offset)
|
603
640
|
if pause and isinstance(pause, (int, float)):
|
604
641
|
time.sleep(pause)
|
605
642
|
|
@@ -607,17 +644,22 @@ class CDPMethods():
|
|
607
644
|
"""Highlight an element with multi-colors."""
|
608
645
|
selector = self.__convert_to_css_if_xpath(selector)
|
609
646
|
element = self.find_element(selector)
|
610
|
-
element.
|
647
|
+
element.scroll_into_view()
|
648
|
+
x_offset = self.__get_x_scroll_offset()
|
649
|
+
y_offset = self.__get_y_scroll_offset()
|
650
|
+
element.flash(0.46, "44CC88", x_offset, y_offset)
|
611
651
|
time.sleep(0.15)
|
612
|
-
element.flash(0.42, "8844CC")
|
652
|
+
element.flash(0.42, "8844CC", x_offset, y_offset)
|
613
653
|
time.sleep(0.15)
|
614
|
-
element.flash(0.38, "CC8844")
|
654
|
+
element.flash(0.38, "CC8844", x_offset, y_offset)
|
615
655
|
time.sleep(0.15)
|
616
|
-
element.flash(0.30, "44CC88")
|
656
|
+
element.flash(0.30, "44CC88", x_offset, y_offset)
|
617
657
|
time.sleep(0.30)
|
618
658
|
|
619
659
|
def focus(self, selector):
|
620
|
-
self.find_element(selector)
|
660
|
+
element = self.find_element(selector)
|
661
|
+
element.scroll_into_view()
|
662
|
+
element.focus()
|
621
663
|
|
622
664
|
def highlight_overlay(self, selector):
|
623
665
|
self.find_element(selector).highlight_overlay()
|
@@ -646,7 +688,7 @@ class CDPMethods():
|
|
646
688
|
def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
|
647
689
|
self.__slow_mode_pause_if_set()
|
648
690
|
element = self.select(selector, timeout=timeout)
|
649
|
-
|
691
|
+
element.scroll_into_view()
|
650
692
|
if text.endswith("\n") or text.endswith("\r"):
|
651
693
|
text = text[:-1] + "\r\n"
|
652
694
|
element.send_keys(text)
|
@@ -657,7 +699,7 @@ class CDPMethods():
|
|
657
699
|
"""Similar to send_keys(), but presses keys at human speed."""
|
658
700
|
self.__slow_mode_pause_if_set()
|
659
701
|
element = self.select(selector, timeout=timeout)
|
660
|
-
|
702
|
+
element.scroll_into_view()
|
661
703
|
submit = False
|
662
704
|
if text.endswith("\n") or text.endswith("\r"):
|
663
705
|
submit = True
|
@@ -675,7 +717,7 @@ class CDPMethods():
|
|
675
717
|
"""Similar to send_keys(), but clears the text field first."""
|
676
718
|
self.__slow_mode_pause_if_set()
|
677
719
|
element = self.select(selector, timeout=timeout)
|
678
|
-
|
720
|
+
element.scroll_into_view()
|
679
721
|
with suppress(Exception):
|
680
722
|
element.clear_input()
|
681
723
|
if text.endswith("\n") or text.endswith("\r"):
|
@@ -688,8 +730,8 @@ class CDPMethods():
|
|
688
730
|
"""Similar to send_keys(), but clears the text field first."""
|
689
731
|
self.__slow_mode_pause_if_set()
|
690
732
|
selector = self.__convert_to_css_if_xpath(selector)
|
691
|
-
self.select(selector, timeout=timeout)
|
692
|
-
|
733
|
+
element = self.select(selector, timeout=timeout)
|
734
|
+
element.scroll_into_view()
|
693
735
|
press_enter = False
|
694
736
|
if text.endswith("\n"):
|
695
737
|
text = text[:-1]
|
@@ -980,8 +1022,10 @@ class CDPMethods():
|
|
980
1022
|
)
|
981
1023
|
|
982
1024
|
def get_element_attribute(self, selector, attribute):
|
983
|
-
|
984
|
-
|
1025
|
+
return self.get_element_attributes(selector)[attribute]
|
1026
|
+
|
1027
|
+
def get_attribute(self, selector, attribute):
|
1028
|
+
return self.find_element(selector).get_attribute(attribute)
|
985
1029
|
|
986
1030
|
def get_element_html(self, selector):
|
987
1031
|
selector = self.__convert_to_css_if_xpath(selector)
|
@@ -1655,17 +1699,24 @@ class CDPMethods():
|
|
1655
1699
|
raise Exception(error % (expected, actual))
|
1656
1700
|
|
1657
1701
|
def assert_text(
|
1658
|
-
self, text, selector="
|
1702
|
+
self, text, selector="body", timeout=settings.SMALL_TIMEOUT
|
1659
1703
|
):
|
1704
|
+
start_ms = time.time() * 1000.0
|
1705
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1660
1706
|
text = text.strip()
|
1661
1707
|
element = None
|
1662
1708
|
try:
|
1663
1709
|
element = self.find_element(selector, timeout=timeout)
|
1664
1710
|
except Exception:
|
1665
1711
|
raise Exception("Element {%s} not found!" % selector)
|
1666
|
-
for i in range(
|
1712
|
+
for i in range(int(timeout * 10)):
|
1713
|
+
with suppress(Exception):
|
1714
|
+
element = self.find_element(selector, timeout=0.1)
|
1667
1715
|
if text in element.text_all:
|
1668
1716
|
return True
|
1717
|
+
now_ms = time.time() * 1000.0
|
1718
|
+
if now_ms >= stop_ms:
|
1719
|
+
break
|
1669
1720
|
time.sleep(0.1)
|
1670
1721
|
raise Exception(
|
1671
1722
|
"Text {%s} not found in {%s}! Actual text: {%s}"
|
@@ -1673,20 +1724,27 @@ class CDPMethods():
|
|
1673
1724
|
)
|
1674
1725
|
|
1675
1726
|
def assert_exact_text(
|
1676
|
-
self, text, selector="
|
1727
|
+
self, text, selector="body", timeout=settings.SMALL_TIMEOUT
|
1677
1728
|
):
|
1729
|
+
start_ms = time.time() * 1000.0
|
1730
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1678
1731
|
text = text.strip()
|
1679
1732
|
element = None
|
1680
1733
|
try:
|
1681
1734
|
element = self.select(selector, timeout=timeout)
|
1682
1735
|
except Exception:
|
1683
1736
|
raise Exception("Element {%s} not found!" % selector)
|
1684
|
-
for i in range(
|
1737
|
+
for i in range(int(timeout * 10)):
|
1738
|
+
with suppress(Exception):
|
1739
|
+
element = self.select(selector, timeout=0.1)
|
1685
1740
|
if (
|
1686
1741
|
self.is_element_visible(selector)
|
1687
1742
|
and text.strip() == element.text_all.strip()
|
1688
1743
|
):
|
1689
1744
|
return True
|
1745
|
+
now_ms = time.time() * 1000.0
|
1746
|
+
if now_ms >= stop_ms:
|
1747
|
+
break
|
1690
1748
|
time.sleep(0.1)
|
1691
1749
|
raise Exception(
|
1692
1750
|
"Expected Text {%s}, is not equal to {%s} in {%s}!"
|
@@ -71,6 +71,8 @@ def set_settings(settings_file):
|
|
71
71
|
settings.LARGE_TIMEOUT = override_settings[key]
|
72
72
|
elif key == "EXTREME_TIMEOUT":
|
73
73
|
settings.EXTREME_TIMEOUT = override_settings[key]
|
74
|
+
elif key == "PAGE_LOAD_TIMEOUT":
|
75
|
+
settings.PAGE_LOAD_TIMEOUT = override_settings[key]
|
74
76
|
elif key == "ARCHIVE_EXISTING_LOGS":
|
75
77
|
settings.ARCHIVE_EXISTING_LOGS = override_settings[key]
|
76
78
|
elif key == "ARCHIVE_EXISTING_DOWNLOADS":
|
@@ -1451,7 +1451,7 @@ class BaseCase(unittest.TestCase):
|
|
1451
1451
|
return self.__is_shadow_element_enabled(selector)
|
1452
1452
|
return page_actions.is_element_enabled(self.driver, selector, by)
|
1453
1453
|
|
1454
|
-
def is_text_visible(self, text, selector="
|
1454
|
+
def is_text_visible(self, text, selector="body", by="css selector"):
|
1455
1455
|
"""Returns whether the text substring is visible in the element."""
|
1456
1456
|
self.wait_for_ready_state_complete()
|
1457
1457
|
time.sleep(0.01)
|
@@ -1460,7 +1460,7 @@ class BaseCase(unittest.TestCase):
|
|
1460
1460
|
return self.__is_shadow_text_visible(text, selector)
|
1461
1461
|
return page_actions.is_text_visible(self.driver, text, selector, by)
|
1462
1462
|
|
1463
|
-
def is_exact_text_visible(self, text, selector="
|
1463
|
+
def is_exact_text_visible(self, text, selector="body", by="css selector"):
|
1464
1464
|
"""Returns whether the text is exactly equal to the element text.
|
1465
1465
|
(Leading and trailing whitespace is ignored in the verification.)"""
|
1466
1466
|
self.wait_for_ready_state_complete()
|
@@ -1472,7 +1472,7 @@ class BaseCase(unittest.TestCase):
|
|
1472
1472
|
self.driver, text, selector, by
|
1473
1473
|
)
|
1474
1474
|
|
1475
|
-
def is_non_empty_text_visible(self, selector="
|
1475
|
+
def is_non_empty_text_visible(self, selector="body", by="css selector"):
|
1476
1476
|
"""Returns whether the element has any non-empty text visible.
|
1477
1477
|
Whitespace-only text is considered empty text."""
|
1478
1478
|
self.wait_for_ready_state_complete()
|
@@ -1842,7 +1842,7 @@ class BaseCase(unittest.TestCase):
|
|
1842
1842
|
elif self.slow_mode:
|
1843
1843
|
self.__slow_mode_pause_if_active()
|
1844
1844
|
|
1845
|
-
def get_text(self, selector="
|
1845
|
+
def get_text(self, selector="body", by="css selector", timeout=None):
|
1846
1846
|
self.__check_scope()
|
1847
1847
|
if not timeout:
|
1848
1848
|
timeout = settings.LARGE_TIMEOUT
|
@@ -2105,7 +2105,7 @@ class BaseCase(unittest.TestCase):
|
|
2105
2105
|
return property_value
|
2106
2106
|
|
2107
2107
|
def get_text_content(
|
2108
|
-
self, selector="
|
2108
|
+
self, selector="body", by="css selector", timeout=None
|
2109
2109
|
):
|
2110
2110
|
"""Returns the text that appears in the HTML for an element.
|
2111
2111
|
This is different from "self.get_text(selector, by="css selector")"
|
@@ -6051,10 +6051,8 @@ class BaseCase(unittest.TestCase):
|
|
6051
6051
|
scroll - the option to scroll to the element first (Default: True)
|
6052
6052
|
timeout - the time to wait for the element to appear """
|
6053
6053
|
self.__check_scope()
|
6054
|
-
if self.__is_cdp_swap_needed()
|
6055
|
-
self.
|
6056
|
-
return
|
6057
|
-
self._check_browser()
|
6054
|
+
if not self.__is_cdp_swap_needed():
|
6055
|
+
self._check_browser()
|
6058
6056
|
self.__skip_if_esc()
|
6059
6057
|
if isinstance(selector, WebElement):
|
6060
6058
|
self.__highlight_element(selector, loops=loops, scroll=scroll)
|
@@ -6093,7 +6091,7 @@ class BaseCase(unittest.TestCase):
|
|
6093
6091
|
if limit > 0 and count >= limit:
|
6094
6092
|
break
|
6095
6093
|
|
6096
|
-
def press_up_arrow(self, selector="
|
6094
|
+
def press_up_arrow(self, selector="body", times=1, by="css selector"):
|
6097
6095
|
"""Simulates pressing the UP Arrow on the keyboard.
|
6098
6096
|
By default, "html" will be used as the CSS Selector target.
|
6099
6097
|
You can specify how many times in-a-row the action happens."""
|
@@ -6115,7 +6113,7 @@ class BaseCase(unittest.TestCase):
|
|
6115
6113
|
if self.slow_mode:
|
6116
6114
|
time.sleep(0.1)
|
6117
6115
|
|
6118
|
-
def press_down_arrow(self, selector="
|
6116
|
+
def press_down_arrow(self, selector="body", times=1, by="css selector"):
|
6119
6117
|
"""Simulates pressing the DOWN Arrow on the keyboard.
|
6120
6118
|
By default, "html" will be used as the CSS Selector target.
|
6121
6119
|
You can specify how many times in-a-row the action happens."""
|
@@ -6137,7 +6135,7 @@ class BaseCase(unittest.TestCase):
|
|
6137
6135
|
if self.slow_mode:
|
6138
6136
|
time.sleep(0.1)
|
6139
6137
|
|
6140
|
-
def press_left_arrow(self, selector="
|
6138
|
+
def press_left_arrow(self, selector="body", times=1, by="css selector"):
|
6141
6139
|
"""Simulates pressing the LEFT Arrow on the keyboard.
|
6142
6140
|
By default, "html" will be used as the CSS Selector target.
|
6143
6141
|
You can specify how many times in-a-row the action happens."""
|
@@ -6159,7 +6157,7 @@ class BaseCase(unittest.TestCase):
|
|
6159
6157
|
if self.slow_mode:
|
6160
6158
|
time.sleep(0.1)
|
6161
6159
|
|
6162
|
-
def press_right_arrow(self, selector="
|
6160
|
+
def press_right_arrow(self, selector="body", times=1, by="css selector"):
|
6163
6161
|
"""Simulates pressing the RIGHT Arrow on the keyboard.
|
6164
6162
|
By default, "html" will be used as the CSS Selector target.
|
6165
6163
|
You can specify how many times in-a-row the action happens."""
|
@@ -9730,7 +9728,7 @@ class BaseCase(unittest.TestCase):
|
|
9730
9728
|
############
|
9731
9729
|
|
9732
9730
|
def wait_for_text_visible(
|
9733
|
-
self, text, selector="
|
9731
|
+
self, text, selector="body", by="css selector", timeout=None
|
9734
9732
|
):
|
9735
9733
|
self.__check_scope()
|
9736
9734
|
if not timeout:
|
@@ -9748,7 +9746,7 @@ class BaseCase(unittest.TestCase):
|
|
9748
9746
|
)
|
9749
9747
|
|
9750
9748
|
def wait_for_exact_text_visible(
|
9751
|
-
self, text, selector="
|
9749
|
+
self, text, selector="body", by="css selector", timeout=None
|
9752
9750
|
):
|
9753
9751
|
self.__check_scope()
|
9754
9752
|
if not timeout:
|
@@ -9765,7 +9763,7 @@ class BaseCase(unittest.TestCase):
|
|
9765
9763
|
)
|
9766
9764
|
|
9767
9765
|
def wait_for_non_empty_text_visible(
|
9768
|
-
self, selector="
|
9766
|
+
self, selector="body", by="css selector", timeout=None
|
9769
9767
|
):
|
9770
9768
|
"""Searches for any text in the element of the given selector.
|
9771
9769
|
Returns the element if it has visible text within the timeout.
|
@@ -9786,7 +9784,7 @@ class BaseCase(unittest.TestCase):
|
|
9786
9784
|
)
|
9787
9785
|
|
9788
9786
|
def wait_for_text(
|
9789
|
-
self, text, selector="
|
9787
|
+
self, text, selector="body", by="css selector", timeout=None
|
9790
9788
|
):
|
9791
9789
|
"""The shorter version of wait_for_text_visible()"""
|
9792
9790
|
self.__check_scope()
|
@@ -9799,7 +9797,7 @@ class BaseCase(unittest.TestCase):
|
|
9799
9797
|
)
|
9800
9798
|
|
9801
9799
|
def wait_for_exact_text(
|
9802
|
-
self, text, selector="
|
9800
|
+
self, text, selector="body", by="css selector", timeout=None
|
9803
9801
|
):
|
9804
9802
|
"""The shorter version of wait_for_exact_text_visible()"""
|
9805
9803
|
self.__check_scope()
|
@@ -9812,7 +9810,7 @@ class BaseCase(unittest.TestCase):
|
|
9812
9810
|
)
|
9813
9811
|
|
9814
9812
|
def wait_for_non_empty_text(
|
9815
|
-
self, selector="
|
9813
|
+
self, selector="body", by="css selector", timeout=None
|
9816
9814
|
):
|
9817
9815
|
"""The shorter version of wait_for_non_empty_text_visible()"""
|
9818
9816
|
self.__check_scope()
|
@@ -9825,7 +9823,7 @@ class BaseCase(unittest.TestCase):
|
|
9825
9823
|
)
|
9826
9824
|
|
9827
9825
|
def find_text(
|
9828
|
-
self, text, selector="
|
9826
|
+
self, text, selector="body", by="css selector", timeout=None
|
9829
9827
|
):
|
9830
9828
|
"""Same as wait_for_text_visible() - returns the element"""
|
9831
9829
|
self.__check_scope()
|
@@ -9838,7 +9836,7 @@ class BaseCase(unittest.TestCase):
|
|
9838
9836
|
)
|
9839
9837
|
|
9840
9838
|
def find_exact_text(
|
9841
|
-
self, text, selector="
|
9839
|
+
self, text, selector="body", by="css selector", timeout=None
|
9842
9840
|
):
|
9843
9841
|
"""Same as wait_for_exact_text_visible() - returns the element"""
|
9844
9842
|
self.__check_scope()
|
@@ -9851,7 +9849,7 @@ class BaseCase(unittest.TestCase):
|
|
9851
9849
|
)
|
9852
9850
|
|
9853
9851
|
def find_non_empty_text(
|
9854
|
-
self, selector="
|
9852
|
+
self, selector="body", by="css selector", timeout=None
|
9855
9853
|
):
|
9856
9854
|
"""Same as wait_for_non_empty_text_visible() - returns the element"""
|
9857
9855
|
self.__check_scope()
|
@@ -9864,7 +9862,7 @@ class BaseCase(unittest.TestCase):
|
|
9864
9862
|
)
|
9865
9863
|
|
9866
9864
|
def assert_text_visible(
|
9867
|
-
self, text, selector="
|
9865
|
+
self, text, selector="body", by="css selector", timeout=None
|
9868
9866
|
):
|
9869
9867
|
"""Same as assert_text()"""
|
9870
9868
|
self.__check_scope()
|
@@ -9875,7 +9873,7 @@ class BaseCase(unittest.TestCase):
|
|
9875
9873
|
return self.assert_text(text, selector, by=by, timeout=timeout)
|
9876
9874
|
|
9877
9875
|
def assert_text(
|
9878
|
-
self, text, selector="
|
9876
|
+
self, text, selector="body", by="css selector", timeout=None
|
9879
9877
|
):
|
9880
9878
|
"""Similar to wait_for_text_visible()
|
9881
9879
|
Raises an exception if the element or the text is not found.
|
@@ -9945,7 +9943,7 @@ class BaseCase(unittest.TestCase):
|
|
9945
9943
|
return True
|
9946
9944
|
|
9947
9945
|
def assert_exact_text(
|
9948
|
-
self, text, selector="
|
9946
|
+
self, text, selector="body", by="css selector", timeout=None
|
9949
9947
|
):
|
9950
9948
|
"""Similar to assert_text(), but the text must be exact,
|
9951
9949
|
rather than exist as a subset of the full text.
|
@@ -9992,7 +9990,7 @@ class BaseCase(unittest.TestCase):
|
|
9992
9990
|
return True
|
9993
9991
|
|
9994
9992
|
def assert_non_empty_text(
|
9995
|
-
self, selector="
|
9993
|
+
self, selector="body", by="css selector", timeout=None
|
9996
9994
|
):
|
9997
9995
|
"""Assert that the element has any non-empty text visible.
|
9998
9996
|
Raises an exception if the element has no text within the timeout.
|
@@ -10279,7 +10277,7 @@ class BaseCase(unittest.TestCase):
|
|
10279
10277
|
############
|
10280
10278
|
|
10281
10279
|
def wait_for_text_not_visible(
|
10282
|
-
self, text, selector="
|
10280
|
+
self, text, selector="body", by="css selector", timeout=None
|
10283
10281
|
):
|
10284
10282
|
self.__check_scope()
|
10285
10283
|
if not timeout:
|
@@ -10292,7 +10290,7 @@ class BaseCase(unittest.TestCase):
|
|
10292
10290
|
)
|
10293
10291
|
|
10294
10292
|
def wait_for_exact_text_not_visible(
|
10295
|
-
self, text, selector="
|
10293
|
+
self, text, selector="body", by="css selector", timeout=None
|
10296
10294
|
):
|
10297
10295
|
self.__check_scope()
|
10298
10296
|
if not timeout:
|
@@ -10305,7 +10303,7 @@ class BaseCase(unittest.TestCase):
|
|
10305
10303
|
)
|
10306
10304
|
|
10307
10305
|
def assert_text_not_visible(
|
10308
|
-
self, text, selector="
|
10306
|
+
self, text, selector="body", by="css selector", timeout=None
|
10309
10307
|
):
|
10310
10308
|
"""Similar to wait_for_text_not_visible()
|
10311
10309
|
Raises an exception if the text is still visible after timeout.
|
@@ -10326,7 +10324,7 @@ class BaseCase(unittest.TestCase):
|
|
10326
10324
|
return True
|
10327
10325
|
|
10328
10326
|
def assert_exact_text_not_visible(
|
10329
|
-
self, text, selector="
|
10327
|
+
self, text, selector="body", by="css selector", timeout=None
|
10330
10328
|
):
|
10331
10329
|
"""Similar to wait_for_exact_text_not_visible()
|
10332
10330
|
Raises an exception if the exact text is still visible after timeout.
|
@@ -11083,7 +11081,7 @@ class BaseCase(unittest.TestCase):
|
|
11083
11081
|
return False
|
11084
11082
|
|
11085
11083
|
def deferred_assert_text(
|
11086
|
-
self, text, selector="
|
11084
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11087
11085
|
):
|
11088
11086
|
"""A non-terminating assertion for text from an element on a page.
|
11089
11087
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11119,7 +11117,7 @@ class BaseCase(unittest.TestCase):
|
|
11119
11117
|
return False
|
11120
11118
|
|
11121
11119
|
def deferred_assert_exact_text(
|
11122
|
-
self, text, selector="
|
11120
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11123
11121
|
):
|
11124
11122
|
"""A non-terminating assertion for exact text from an element.
|
11125
11123
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11158,7 +11156,7 @@ class BaseCase(unittest.TestCase):
|
|
11158
11156
|
|
11159
11157
|
def deferred_assert_non_empty_text(
|
11160
11158
|
self,
|
11161
|
-
selector="
|
11159
|
+
selector="body",
|
11162
11160
|
by="css selector",
|
11163
11161
|
timeout=None,
|
11164
11162
|
fs=False,
|
@@ -11278,7 +11276,7 @@ class BaseCase(unittest.TestCase):
|
|
11278
11276
|
)
|
11279
11277
|
|
11280
11278
|
def delayed_assert_text(
|
11281
|
-
self, text, selector="
|
11279
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11282
11280
|
):
|
11283
11281
|
"""Same as self.deferred_assert_text()"""
|
11284
11282
|
return self.deferred_assert_text(
|
@@ -11286,7 +11284,7 @@ class BaseCase(unittest.TestCase):
|
|
11286
11284
|
)
|
11287
11285
|
|
11288
11286
|
def delayed_assert_exact_text(
|
11289
|
-
self, text, selector="
|
11287
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11290
11288
|
):
|
11291
11289
|
"""Same as self.deferred_assert_exact_text()"""
|
11292
11290
|
return self.deferred_assert_exact_text(
|
@@ -11295,7 +11293,7 @@ class BaseCase(unittest.TestCase):
|
|
11295
11293
|
|
11296
11294
|
def delayed_assert_non_empty_text(
|
11297
11295
|
self,
|
11298
|
-
selector="
|
11296
|
+
selector="body",
|
11299
11297
|
by="css selector",
|
11300
11298
|
timeout=None,
|
11301
11299
|
fs=False,
|
@@ -13860,7 +13858,8 @@ class BaseCase(unittest.TestCase):
|
|
13860
13858
|
js_utils.scroll_to_element(self.driver, element)
|
13861
13859
|
|
13862
13860
|
def __highlight_with_js(self, selector, loops, o_bs):
|
13863
|
-
self.
|
13861
|
+
if not self.__is_cdp_swap_needed():
|
13862
|
+
self.wait_for_ready_state_complete()
|
13864
13863
|
js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
|
13865
13864
|
|
13866
13865
|
def __highlight_element_with_js(self, element, loops, o_bs):
|
@@ -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
|
|
@@ -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,16 @@ 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
|
+
|
131
142
|
def make_writable(file_path):
|
132
143
|
# Set permissions to: "If you can read it, you can write it."
|
133
144
|
mode = os.stat(file_path).st_mode
|
@@ -2143,6 +2143,9 @@ def _perform_pytest_unconfigure_(config):
|
|
2143
2143
|
log_helper.archive_logs_if_set(
|
2144
2144
|
constants.Logs.LATEST + "/", sb_config.archive_logs
|
2145
2145
|
)
|
2146
|
+
if os.path.exists("./assets/"): # Used by pytest-html reports
|
2147
|
+
with suppress(Exception):
|
2148
|
+
shared_utils.make_dir_files_writable("./assets/")
|
2146
2149
|
log_helper.clear_empty_logs()
|
2147
2150
|
# Dashboard post-processing: Disable time-based refresh and stamp complete
|
2148
2151
|
if not hasattr(sb_config, "dashboard") or not sb_config.dashboard:
|
@@ -2207,8 +2210,12 @@ def _perform_pytest_unconfigure_(config):
|
|
2207
2210
|
)
|
2208
2211
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2209
2212
|
f.write(the_html_r) # Finalize the HTML report
|
2213
|
+
with suppress(Exception):
|
2214
|
+
shared_utils.make_writable(html_report_path)
|
2210
2215
|
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2211
|
-
f.write(the_html_r) # Finalize the HTML report
|
2216
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2217
|
+
with suppress(Exception):
|
2218
|
+
shared_utils.make_writable(html_report_path_copy)
|
2212
2219
|
assets_style = "./assets/style.css"
|
2213
2220
|
if os.path.exists(assets_style):
|
2214
2221
|
html_style = None
|
@@ -2223,6 +2230,8 @@ def _perform_pytest_unconfigure_(config):
|
|
2223
2230
|
)
|
2224
2231
|
with open(assets_style, "w", encoding="utf-8") as f:
|
2225
2232
|
f.write(html_style)
|
2233
|
+
with suppress(Exception):
|
2234
|
+
shared_utils.make_writable(assets_style)
|
2226
2235
|
# Done with "pytest_unconfigure" unless using the Dashboard
|
2227
2236
|
return
|
2228
2237
|
stamp = ""
|
@@ -2304,6 +2313,8 @@ def _perform_pytest_unconfigure_(config):
|
|
2304
2313
|
)
|
2305
2314
|
with open(dashboard_path, "w", encoding="utf-8") as f:
|
2306
2315
|
f.write(the_html_d) # Finalize the dashboard
|
2316
|
+
with suppress(Exception):
|
2317
|
+
shared_utils.make_writable(dashboard_path)
|
2307
2318
|
assets_style = "./assets/style.css"
|
2308
2319
|
if os.path.exists(assets_style):
|
2309
2320
|
html_style = None
|
@@ -2318,6 +2329,8 @@ def _perform_pytest_unconfigure_(config):
|
|
2318
2329
|
)
|
2319
2330
|
with open(assets_style, "w", encoding="utf-8") as f:
|
2320
2331
|
f.write(html_style)
|
2332
|
+
with suppress(Exception):
|
2333
|
+
shared_utils.make_writable(assets_style)
|
2321
2334
|
# Part 2: Appending a pytest html report with dashboard data
|
2322
2335
|
html_report_path = None
|
2323
2336
|
if sb_config._html_report_name:
|
@@ -2398,8 +2411,12 @@ def _perform_pytest_unconfigure_(config):
|
|
2398
2411
|
)
|
2399
2412
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2400
2413
|
f.write(the_html_r) # Finalize the HTML report
|
2414
|
+
with suppress(Exception):
|
2415
|
+
shared_utils.make_writable(html_report_path)
|
2401
2416
|
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2402
|
-
f.write(the_html_r) # Finalize the HTML report
|
2417
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2418
|
+
with suppress(Exception):
|
2419
|
+
shared_utils.make_writable(html_report_path_copy)
|
2403
2420
|
except KeyboardInterrupt:
|
2404
2421
|
pass
|
2405
2422
|
except Exception:
|
@@ -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
|
|
@@ -883,6 +880,8 @@ class Element:
|
|
883
880
|
self,
|
884
881
|
duration: typing.Union[float, int] = 0.5,
|
885
882
|
color: typing.Optional[str] = "EE4488",
|
883
|
+
x_offset: typing.Union[float, int] = 0,
|
884
|
+
y_offset: typing.Union[float, int] = 0,
|
886
885
|
):
|
887
886
|
"""
|
888
887
|
Displays for a short time a red dot on the element.
|
@@ -910,8 +909,8 @@ class Element:
|
|
910
909
|
"width:8px;height:8px;border-radius:50%;background:#{};"
|
911
910
|
"animation:show-pointer-ani {:.2f}s ease 1;"
|
912
911
|
).format(
|
913
|
-
pos.center[0] - 4, # -4 to account for
|
914
|
-
pos.center[1] - 4,
|
912
|
+
pos.center[0] + x_offset - 4, # -4 to account for the circle
|
913
|
+
pos.center[1] + y_offset - 4, # -4 to account for the circle
|
915
914
|
color,
|
916
915
|
duration,
|
917
916
|
)
|
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
|
|
3
3
|
sbase/steps.py,sha256=_WvAjydKqZfTdnZW9LPKkRty-g-lfdUPmLqnZj6ulcs,43013
|
4
4
|
seleniumbase/__init__.py,sha256=OtJh8nGKL4xtZpw8KPqmn7Q6R-86t4cWUDyVF5MbMTo,2398
|
5
5
|
seleniumbase/__main__.py,sha256=dn1p6dgCchmcH1zzTzzQvFwwdQQqnTGH6ULV9m4hv24,654
|
6
|
-
seleniumbase/__version__.py,sha256=
|
6
|
+
seleniumbase/__version__.py,sha256=rd7NUV3t0KKsPu_LnXrJlAcYzq8npXhiWbpSgIR17LE,46
|
7
7
|
seleniumbase/behave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
seleniumbase/behave/behave_helper.py,sha256=elkl8P9eLulRAioLstE9baYNM9N_PHBmAOcajX-pH_Y,24198
|
9
9
|
seleniumbase/behave/behave_sb.py,sha256=-hza7Nx2U41mSObYiPMi48v3JlPh3sJO3yzP0kqZ1Gk,59174
|
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
|
|
36
36
|
seleniumbase/console_scripts/sb_recorder.py,sha256=fnHb5-kh11Hit-E9Ha-e4QXzqLcZvtij6mb5qNd4B1Q,11032
|
37
37
|
seleniumbase/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
38
|
seleniumbase/core/application_manager.py,sha256=e_0sjtI8cjY5BNyZj1QBR0j6_oCScxGmSXYEpcYwuZE,576
|
39
|
-
seleniumbase/core/browser_launcher.py,sha256=
|
39
|
+
seleniumbase/core/browser_launcher.py,sha256=FvcxXqCiE4yelqDBQjXVY4b7UubfzhI67IIWvjJMDe4,224583
|
40
40
|
seleniumbase/core/capabilities_parser.py,sha256=meIS2uHapTCq2ldfNAToC7r0cKmZDRXuYNKExM1GHDY,6038
|
41
41
|
seleniumbase/core/colored_traceback.py,sha256=DrRWfg7XEnKcgY59Xj7Jdk09H-XqHYBSUpB-DiZt6iY,2020
|
42
42
|
seleniumbase/core/create_db_tables.sql,sha256=VWPtrdiW_HQ6yETHjqTu-VIrTwvd8I8o1NfBeaVSHpU,972
|
@@ -44,16 +44,16 @@ seleniumbase/core/detect_b_ver.py,sha256=RxeGRMbBUTMrXh5KsS1P1SH7eEKYbzL1vQw1gTd
|
|
44
44
|
seleniumbase/core/download_helper.py,sha256=qSR54kQISucF4RQaLCOuuerSu6DR41juGi_30HVvWYY,2943
|
45
45
|
seleniumbase/core/encoded_images.py,sha256=rDKJ4cNJSuKiRcFViYU7bjyTS9_moI57gUPRXVg3u2k,14209
|
46
46
|
seleniumbase/core/jqc_helper.py,sha256=2DDQr9Q2jSSZqFzX588jLlUM9oJvyrRWq2aORSIPUdI,10322
|
47
|
-
seleniumbase/core/log_helper.py,sha256=
|
47
|
+
seleniumbase/core/log_helper.py,sha256=N0YbsRy8sEoGQu4BjiAJHC5mK_ydl0YLgRp6jAcwwos,22987
|
48
48
|
seleniumbase/core/mysql.py,sha256=8Fzj3p5dhtDWfMpFqFYxpSwa9s1UltiHsWJ56_aPOqk,3993
|
49
|
-
seleniumbase/core/proxy_helper.py,sha256=
|
49
|
+
seleniumbase/core/proxy_helper.py,sha256=kZnfkflB3XhuL2h-3inmx3UOLS8VAZ385BGCc4H8TvU,8267
|
50
50
|
seleniumbase/core/recorder_helper.py,sha256=fNGjbapXmEsht54x1o6Igk198QdnPxDDnjUOzQxNhNQ,25055
|
51
51
|
seleniumbase/core/report_helper.py,sha256=AIl6Qava2yW1uSzbLpJBlPlYDz0KE-rVhogh8hsGWBo,12201
|
52
52
|
seleniumbase/core/s3_manager.py,sha256=bkeI8I4y19ebWuQG1oEZV5qJbotC6eN8vin31OCNWJk,3521
|
53
|
-
seleniumbase/core/sb_cdp.py,sha256=
|
53
|
+
seleniumbase/core/sb_cdp.py,sha256=zFFpaQZTBpjMLhVX_Ll9hOqKnZLJstTgmiU8-LFbvwo,70647
|
54
54
|
seleniumbase/core/sb_driver.py,sha256=NGa4adi8OAi2WFtFkEguXg3JCd1p-JuZweIpGNifEfU,13488
|
55
55
|
seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
|
56
|
-
seleniumbase/core/settings_parser.py,sha256=
|
56
|
+
seleniumbase/core/settings_parser.py,sha256=gqVohHVlE_5L5Cqe2L24uYrRzvoK-saX8E_Df7_-_3I,7609
|
57
57
|
seleniumbase/core/style_sheet.py,sha256=QsfTBtgedfM3uTqgxtd53bhq202p9fwLMbFl9mPZgVg,11892
|
58
58
|
seleniumbase/core/testcase_manager.py,sha256=TblCfo8Zfap1Bayip-qTu9gqT-KALSwXAX4awBpnEHg,4633
|
59
59
|
seleniumbase/core/tour_helper.py,sha256=kj2cz-DGKlw9SX3tWnVp-snpk6Flvqj81-xmKdKDtg0,42555
|
@@ -65,14 +65,14 @@ seleniumbase/extensions/disable_csp.zip,sha256=YMifIIgEBiLrEFrS1sfW4Exh4br1V4oK1
|
|
65
65
|
seleniumbase/extensions/recorder.zip,sha256=OOyzF-Ize2cSRu1CqhzSAq5vusI9hqLLd2OIApUHesI,11918
|
66
66
|
seleniumbase/extensions/sbase_ext.zip,sha256=3s1N8zrVaMz8RQEOIoBzC3KDjtmHwVZRvVsX25Odr_s,8175
|
67
67
|
seleniumbase/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
68
|
-
seleniumbase/fixtures/base_case.py,sha256=
|
68
|
+
seleniumbase/fixtures/base_case.py,sha256=DY-UpQRyfl8ZzA-D-5cKJKwm2kAXeE7L06rgMRDz3Xw,718513
|
69
69
|
seleniumbase/fixtures/constants.py,sha256=e1LppavlrAcI4XBJMq7u5j8SffaQ7SPQps1y0YvZYfY,13649
|
70
70
|
seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
|
71
71
|
seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
|
72
|
-
seleniumbase/fixtures/js_utils.py,sha256=
|
72
|
+
seleniumbase/fixtures/js_utils.py,sha256=asZJ0LDFv2BPQOzUVKK_9ie8ToGcmFousDnGdb3Vabg,51534
|
73
73
|
seleniumbase/fixtures/page_actions.py,sha256=dbp63c-7asYZyd8aOu57Y3dxQQozp_VJsP5h74s1kBA,66552
|
74
74
|
seleniumbase/fixtures/page_utils.py,sha256=5m7iXpikLs80TJoRO6_gEfXE1AKeQgcH1aFbR8o1C9A,12034
|
75
|
-
seleniumbase/fixtures/shared_utils.py,sha256=
|
75
|
+
seleniumbase/fixtures/shared_utils.py,sha256=G6CsE-Adt-GfuZF-71jXWKSIQW7YZPx8FIM24pVd_yI,8368
|
76
76
|
seleniumbase/fixtures/unittest_helper.py,sha256=sfZ92rZeBAn_sF_yQ3I6_I7h3lyU5-cV_UMegBNoEm8,1294
|
77
77
|
seleniumbase/fixtures/words.py,sha256=FOA4mAYvl3EPVpBTvgvK6YwCL8BdlRCmed685kEe7Vg,7827
|
78
78
|
seleniumbase/fixtures/xpath_to_css.py,sha256=lML56k656fElXJ4NJF07r35FjctrbgQkXUotNk7A-as,8876
|
@@ -88,7 +88,7 @@ seleniumbase/plugins/basic_test_info.py,sha256=8ov6n417gPbqqvrlT4zrch7l2XcRt-GF2
|
|
88
88
|
seleniumbase/plugins/db_reporting_plugin.py,sha256=En09qUCoojrk9-vbcnsoHdSELoGmag2GDIyu3jTiJas,7331
|
89
89
|
seleniumbase/plugins/driver_manager.py,sha256=s20s0pJYaNrG0WNwyIC04oUMRVFjtm6V_nS1-EvFm7g,34492
|
90
90
|
seleniumbase/plugins/page_source.py,sha256=loTnXxOj4kxEukuTZEiGyvKBhY3KDVDMnNlHHheTBDE,1889
|
91
|
-
seleniumbase/plugins/pytest_plugin.py,sha256=
|
91
|
+
seleniumbase/plugins/pytest_plugin.py,sha256=JjpglUqHkfl6rzdg1SkJ7PMtNRpceOgLNbUi2DyKpJI,105416
|
92
92
|
seleniumbase/plugins/s3_logging_plugin.py,sha256=WDfertQgGOW_SRJpFMaekYD6vBVW9VO62POtXXy2HCM,2319
|
93
93
|
seleniumbase/plugins/sb_manager.py,sha256=qCf6RAkAfziLTGgiJvB3V416RxWoTbRLm9wc-KsB8g8,54419
|
94
94
|
seleniumbase/plugins/screen_shots.py,sha256=1hrXw-hzuZ1BR6Yh7AyWX2ABnvnP73-RCbwdz958gj4,1127
|
@@ -117,9 +117,9 @@ seleniumbase/undetected/cdp_driver/__init__.py,sha256=c0TjMwPfVFyoqYOJ7PQ-Jln_L_
|
|
117
117
|
seleniumbase/undetected/cdp_driver/_contradict.py,sha256=6thDYeoEGiC7Q3tXLgoD_AhxecCFnATzBSjNympyRHA,3184
|
118
118
|
seleniumbase/undetected/cdp_driver/browser.py,sha256=n8GYspU7b0pfBT4AqhqY6IdGVOZ1FC4wJ5emIOl-khQ,30129
|
119
119
|
seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=YhtD2Tm6PLIy9VKbgk8lHdGniS3mObyX4yAC1aG0TgQ,16733
|
120
|
-
seleniumbase/undetected/cdp_driver/config.py,sha256=
|
120
|
+
seleniumbase/undetected/cdp_driver/config.py,sha256=oHFJ3UH0OmLmEGgG5S6SZwbyBs9ZYMsbUJ02QCA7iZc,12044
|
121
121
|
seleniumbase/undetected/cdp_driver/connection.py,sha256=sOTUGjbUqKA2hPvDcRCdqw1VQjVGJs7mbgVvzS7ldtE,23360
|
122
|
-
seleniumbase/undetected/cdp_driver/element.py,sha256=
|
122
|
+
seleniumbase/undetected/cdp_driver/element.py,sha256=LMnHQO-n0DvBo3Fb5G6X8cOaAvqxHgTZj8JHCTfWZjQ,40377
|
123
123
|
seleniumbase/undetected/cdp_driver/tab.py,sha256=cmSUg9fRnIVYgeqs-t8Tcg1FrSVIrM5IBQmCMzvl4OQ,50678
|
124
124
|
seleniumbase/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
125
125
|
seleniumbase/utilities/selenium_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -135,9 +135,9 @@ seleniumbase/utilities/selenium_grid/start-grid-hub.bat,sha256=Ftq-GrAKRYH2ssDPr
|
|
135
135
|
seleniumbase/utilities/selenium_grid/start-grid-hub.sh,sha256=KADv0RUHONLL2_I443QFK8PryBpDmKn5Gy0s4o0vDSM,106
|
136
136
|
seleniumbase/utilities/selenium_ide/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
137
137
|
seleniumbase/utilities/selenium_ide/convert_ide.py,sha256=pZFnqEJQEKZPyNFjkLD29s2HPQgCrWW9XJWpCPhWOoM,31691
|
138
|
-
seleniumbase-4.33.
|
139
|
-
seleniumbase-4.33.
|
140
|
-
seleniumbase-4.33.
|
141
|
-
seleniumbase-4.33.
|
142
|
-
seleniumbase-4.33.
|
143
|
-
seleniumbase-4.33.
|
138
|
+
seleniumbase-4.33.8.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
|
139
|
+
seleniumbase-4.33.8.dist-info/METADATA,sha256=ZVgDox3MKzCN1oVyAWbfy8UuHNqF6JRsygiFvUjAGYE,86528
|
140
|
+
seleniumbase-4.33.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
141
|
+
seleniumbase-4.33.8.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
|
142
|
+
seleniumbase-4.33.8.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
|
143
|
+
seleniumbase-4.33.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|