seleniumbase 4.24.10__py3-none-any.whl → 4.33.15__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.
- sbase/__init__.py +1 -0
- sbase/steps.py +7 -0
- seleniumbase/__init__.py +16 -7
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +97 -32
- seleniumbase/common/decorators.py +16 -7
- seleniumbase/config/proxy_list.py +3 -3
- seleniumbase/config/settings.py +4 -0
- seleniumbase/console_scripts/logo_helper.py +47 -8
- seleniumbase/console_scripts/run.py +345 -335
- seleniumbase/console_scripts/sb_behave_gui.py +5 -12
- seleniumbase/console_scripts/sb_caseplans.py +6 -13
- seleniumbase/console_scripts/sb_commander.py +5 -12
- seleniumbase/console_scripts/sb_install.py +62 -54
- seleniumbase/console_scripts/sb_mkchart.py +13 -20
- seleniumbase/console_scripts/sb_mkdir.py +11 -17
- seleniumbase/console_scripts/sb_mkfile.py +69 -43
- seleniumbase/console_scripts/sb_mkpres.py +13 -20
- seleniumbase/console_scripts/sb_mkrec.py +88 -21
- seleniumbase/console_scripts/sb_objectify.py +30 -30
- seleniumbase/console_scripts/sb_print.py +5 -12
- seleniumbase/console_scripts/sb_recorder.py +16 -11
- seleniumbase/core/browser_launcher.py +1658 -221
- seleniumbase/core/detect_b_ver.py +7 -8
- seleniumbase/core/log_helper.py +42 -27
- seleniumbase/core/mysql.py +1 -4
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/recorder_helper.py +24 -5
- seleniumbase/core/sb_cdp.py +1951 -0
- seleniumbase/core/sb_driver.py +162 -8
- seleniumbase/core/settings_parser.py +6 -0
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/extensions/recorder.zip +0 -0
- seleniumbase/fixtures/base_case.py +1234 -632
- seleniumbase/fixtures/constants.py +10 -1
- seleniumbase/fixtures/js_utils.py +171 -144
- seleniumbase/fixtures/page_actions.py +177 -13
- seleniumbase/fixtures/page_utils.py +25 -53
- seleniumbase/fixtures/shared_utils.py +97 -11
- seleniumbase/js_code/active_css_js.py +1 -1
- seleniumbase/js_code/recorder_js.py +1 -1
- seleniumbase/plugins/base_plugin.py +2 -3
- seleniumbase/plugins/driver_manager.py +340 -65
- seleniumbase/plugins/pytest_plugin.py +276 -47
- seleniumbase/plugins/sb_manager.py +412 -99
- seleniumbase/plugins/selenium_plugin.py +122 -17
- seleniumbase/translate/translator.py +0 -7
- seleniumbase/undetected/__init__.py +59 -52
- seleniumbase/undetected/cdp.py +0 -1
- seleniumbase/undetected/cdp_driver/__init__.py +1 -0
- seleniumbase/undetected/cdp_driver/_contradict.py +110 -0
- seleniumbase/undetected/cdp_driver/browser.py +829 -0
- seleniumbase/undetected/cdp_driver/cdp_util.py +458 -0
- seleniumbase/undetected/cdp_driver/config.py +334 -0
- seleniumbase/undetected/cdp_driver/connection.py +639 -0
- seleniumbase/undetected/cdp_driver/element.py +1168 -0
- seleniumbase/undetected/cdp_driver/tab.py +1323 -0
- seleniumbase/undetected/dprocess.py +4 -7
- seleniumbase/undetected/options.py +6 -8
- seleniumbase/undetected/patcher.py +11 -13
- seleniumbase/undetected/reactor.py +0 -1
- seleniumbase/undetected/webelement.py +16 -3
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +68 -70
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/WHEEL +1 -1
- sbase/ReadMe.txt +0 -2
- seleniumbase/ReadMe.md +0 -25
- seleniumbase/common/ReadMe.md +0 -71
- seleniumbase/console_scripts/ReadMe.md +0 -731
- seleniumbase/drivers/ReadMe.md +0 -27
- seleniumbase/extensions/ReadMe.md +0 -12
- seleniumbase/masterqa/ReadMe.md +0 -61
- seleniumbase/resources/ReadMe.md +0 -31
- seleniumbase/resources/favicon.ico +0 -0
- seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
- seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/top_level.txt +0 -0
@@ -33,6 +33,7 @@ Page elements are given enough time to load before WebDriver acts on them.
|
|
33
33
|
Code becomes greatly simplified and easier to maintain."""
|
34
34
|
|
35
35
|
import codecs
|
36
|
+
import colorama
|
36
37
|
import fasteners
|
37
38
|
import json
|
38
39
|
import logging
|
@@ -45,7 +46,7 @@ import textwrap
|
|
45
46
|
import time
|
46
47
|
import unittest
|
47
48
|
import urllib3
|
48
|
-
from contextlib import contextmanager
|
49
|
+
from contextlib import contextmanager, suppress
|
49
50
|
from selenium.common.exceptions import (
|
50
51
|
ElementClickInterceptedException as ECI_Exception,
|
51
52
|
ElementNotInteractableException as ENI_Exception,
|
@@ -57,9 +58,11 @@ from selenium.common.exceptions import (
|
|
57
58
|
TimeoutException,
|
58
59
|
WebDriverException,
|
59
60
|
)
|
61
|
+
from selenium.webdriver.common.action_chains import ActionChains
|
60
62
|
from selenium.webdriver.common.by import By
|
61
63
|
from selenium.webdriver.common.keys import Keys
|
62
64
|
from selenium.webdriver.remote.remote_connection import LOGGER
|
65
|
+
from selenium.webdriver.remote.webelement import WebElement
|
63
66
|
from seleniumbase import config as sb_config
|
64
67
|
from seleniumbase.__version__ import __version__
|
65
68
|
from seleniumbase.common import decorators
|
@@ -72,9 +75,11 @@ from seleniumbase.common.exceptions import (
|
|
72
75
|
VisualException,
|
73
76
|
)
|
74
77
|
from seleniumbase.config import settings
|
78
|
+
from seleniumbase.core import browser_launcher
|
75
79
|
from seleniumbase.core import download_helper
|
76
80
|
from seleniumbase.core import log_helper
|
77
81
|
from seleniumbase.core import session_helper
|
82
|
+
from seleniumbase.core import visual_helper
|
78
83
|
from seleniumbase.fixtures import constants
|
79
84
|
from seleniumbase.fixtures import css_to_xpath
|
80
85
|
from seleniumbase.fixtures import js_utils
|
@@ -113,6 +118,7 @@ class BaseCase(unittest.TestCase):
|
|
113
118
|
]
|
114
119
|
self.version_tuple = tuple(self.version_list)
|
115
120
|
self.version_info = self.version_tuple
|
121
|
+
self.time = time.time
|
116
122
|
self.__page_sources = []
|
117
123
|
self.__extra_actions = []
|
118
124
|
self.__js_start_time = 0
|
@@ -178,6 +184,8 @@ class BaseCase(unittest.TestCase):
|
|
178
184
|
self._chart_series_count = {}
|
179
185
|
self._tour_steps = {}
|
180
186
|
self._xvfb_display = None
|
187
|
+
self._xvfb_width = None
|
188
|
+
self._xvfb_height = None
|
181
189
|
|
182
190
|
@classmethod
|
183
191
|
def main(self, name, file, *args):
|
@@ -215,14 +223,15 @@ class BaseCase(unittest.TestCase):
|
|
215
223
|
def open(self, url):
|
216
224
|
"""Navigates the current browser window to the specified page."""
|
217
225
|
self.__check_scope()
|
226
|
+
if self.__is_cdp_swap_needed():
|
227
|
+
self.cdp.open(url)
|
228
|
+
return
|
218
229
|
self._check_browser()
|
219
230
|
if self.__needs_minimum_wait():
|
220
231
|
time.sleep(0.04)
|
221
232
|
pre_action_url = None
|
222
|
-
|
233
|
+
with suppress(Exception):
|
223
234
|
pre_action_url = self.driver.current_url
|
224
|
-
except Exception:
|
225
|
-
pass
|
226
235
|
url = str(url).strip() # Remove leading and trailing whitespace
|
227
236
|
if not self.__looks_like_a_page_url(url):
|
228
237
|
# url should start with one of the following:
|
@@ -350,18 +359,12 @@ class BaseCase(unittest.TestCase):
|
|
350
359
|
if self.undetectable:
|
351
360
|
self.__uc_frame_layer = 0
|
352
361
|
if self.demo_mode:
|
353
|
-
if (
|
354
|
-
self.driver.current_url.startswith("http")
|
355
|
-
or self.driver.current_url.startswith("file")
|
356
|
-
or self.driver.current_url.startswith("data")
|
357
|
-
):
|
362
|
+
if self.driver.current_url.startswith(("http", "file", "data")):
|
358
363
|
if not js_utils.is_jquery_activated(self.driver):
|
359
|
-
|
364
|
+
with suppress(Exception):
|
360
365
|
js_utils.add_js_link(
|
361
366
|
self.driver, constants.JQuery.MIN_JS
|
362
367
|
)
|
363
|
-
except Exception:
|
364
|
-
pass
|
365
368
|
self.__demo_mode_pause_if_active()
|
366
369
|
|
367
370
|
def get(self, url):
|
@@ -380,6 +383,7 @@ class BaseCase(unittest.TestCase):
|
|
380
383
|
self, selector, by="css selector", timeout=None, delay=0, scroll=True
|
381
384
|
):
|
382
385
|
self.__check_scope()
|
386
|
+
self.__skip_if_esc()
|
383
387
|
if not timeout:
|
384
388
|
timeout = settings.SMALL_TIMEOUT
|
385
389
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
@@ -387,6 +391,9 @@ class BaseCase(unittest.TestCase):
|
|
387
391
|
original_selector = selector
|
388
392
|
original_by = by
|
389
393
|
selector, by = self.__recalculate_selector(selector, by)
|
394
|
+
if self.__is_cdp_swap_needed():
|
395
|
+
self.cdp.click(selector, timeout=timeout)
|
396
|
+
return
|
390
397
|
if delay and (type(delay) in [int, float]) and delay > 0:
|
391
398
|
time.sleep(delay)
|
392
399
|
if page_utils.is_link_text_selector(selector) or by == By.LINK_TEXT:
|
@@ -418,10 +425,8 @@ class BaseCase(unittest.TestCase):
|
|
418
425
|
if scroll and not self.demo_mode and not self.slow_mode:
|
419
426
|
self.__scroll_to_element(element, selector, by)
|
420
427
|
pre_action_url = None
|
421
|
-
|
428
|
+
with suppress(Exception):
|
422
429
|
pre_action_url = self.driver.current_url
|
423
|
-
except Exception:
|
424
|
-
pass
|
425
430
|
pre_window_count = len(self.driver.window_handles)
|
426
431
|
try:
|
427
432
|
if (
|
@@ -435,7 +440,7 @@ class BaseCase(unittest.TestCase):
|
|
435
440
|
href = None
|
436
441
|
new_tab = False
|
437
442
|
onclick = None
|
438
|
-
|
443
|
+
with suppress(Exception):
|
439
444
|
if self.headless and element.tag_name.lower() == "a":
|
440
445
|
# Handle a special case of opening a new tab (headless)
|
441
446
|
href = element.get_attribute("href").strip()
|
@@ -445,20 +450,14 @@ class BaseCase(unittest.TestCase):
|
|
445
450
|
new_tab = True
|
446
451
|
if new_tab and self.__looks_like_a_page_url(href):
|
447
452
|
if onclick:
|
448
|
-
|
453
|
+
with suppress(Exception):
|
449
454
|
self.execute_script(onclick)
|
450
|
-
except Exception:
|
451
|
-
pass
|
452
455
|
current_window = self.driver.current_window_handle
|
453
456
|
self.open_new_window()
|
454
|
-
|
457
|
+
with suppress(Exception):
|
455
458
|
self.open(href)
|
456
|
-
except Exception:
|
457
|
-
pass
|
458
459
|
self.switch_to_window(current_window)
|
459
460
|
return
|
460
|
-
except Exception:
|
461
|
-
pass
|
462
461
|
# Normal click
|
463
462
|
self.__element_click(element)
|
464
463
|
except Stale_Exception:
|
@@ -471,10 +470,8 @@ class BaseCase(unittest.TestCase):
|
|
471
470
|
timeout=timeout,
|
472
471
|
original_selector=original_selector,
|
473
472
|
)
|
474
|
-
|
473
|
+
with suppress(Exception):
|
475
474
|
self.__scroll_to_element(element, selector, by)
|
476
|
-
except Exception:
|
477
|
-
pass
|
478
475
|
if self.browser == "safari" and by == By.LINK_TEXT:
|
479
476
|
self.__jquery_click(selector, by=by)
|
480
477
|
elif self.browser == "safari":
|
@@ -482,7 +479,7 @@ class BaseCase(unittest.TestCase):
|
|
482
479
|
else:
|
483
480
|
self.__element_click(element)
|
484
481
|
except ENI_Exception as e:
|
485
|
-
|
482
|
+
with suppress(Exception):
|
486
483
|
if (
|
487
484
|
"element has zero size" in e.msg
|
488
485
|
and element.tag_name.lower() == "a"
|
@@ -494,8 +491,6 @@ class BaseCase(unittest.TestCase):
|
|
494
491
|
if self.__needs_minimum_wait():
|
495
492
|
time.sleep(0.04)
|
496
493
|
return
|
497
|
-
except Exception:
|
498
|
-
pass
|
499
494
|
self.wait_for_ready_state_complete()
|
500
495
|
time.sleep(0.1)
|
501
496
|
element = page_actions.wait_for_element_visible(
|
@@ -508,12 +503,10 @@ class BaseCase(unittest.TestCase):
|
|
508
503
|
if not page_actions.is_element_clickable(
|
509
504
|
self.driver, selector, by
|
510
505
|
):
|
511
|
-
|
506
|
+
with suppress(Exception):
|
512
507
|
self.wait_for_element_clickable(
|
513
508
|
selector, by, timeout=1.8
|
514
509
|
)
|
515
|
-
except Exception:
|
516
|
-
pass # Find out which element would get the click instead
|
517
510
|
element = page_actions.wait_for_element_visible(
|
518
511
|
self.driver,
|
519
512
|
selector,
|
@@ -524,7 +517,7 @@ class BaseCase(unittest.TestCase):
|
|
524
517
|
href = None
|
525
518
|
new_tab = False
|
526
519
|
onclick = None
|
527
|
-
|
520
|
+
with suppress(Exception):
|
528
521
|
if element.tag_name.lower() == "a":
|
529
522
|
# Handle a special case of opening a new tab (non-headless)
|
530
523
|
href = element.get_attribute("href").strip()
|
@@ -534,20 +527,14 @@ class BaseCase(unittest.TestCase):
|
|
534
527
|
new_tab = True
|
535
528
|
if new_tab and self.__looks_like_a_page_url(href):
|
536
529
|
if onclick:
|
537
|
-
|
530
|
+
with suppress(Exception):
|
538
531
|
self.execute_script(onclick)
|
539
|
-
except Exception:
|
540
|
-
pass
|
541
532
|
current_window = self.driver.current_window_handle
|
542
533
|
self.open_new_window()
|
543
|
-
|
534
|
+
with suppress(Exception):
|
544
535
|
self.open(href)
|
545
|
-
except Exception:
|
546
|
-
pass
|
547
536
|
self.switch_to_window(current_window)
|
548
537
|
return
|
549
|
-
except Exception:
|
550
|
-
pass
|
551
538
|
if scroll and not self.demo_mode and not self.slow_mode:
|
552
539
|
self.__scroll_to_element(element, selector, by)
|
553
540
|
if self.browser == "firefox" or self.browser == "safari":
|
@@ -629,10 +616,8 @@ class BaseCase(unittest.TestCase):
|
|
629
616
|
self.switch_to_window(-1)
|
630
617
|
if settings.WAIT_FOR_RSC_ON_CLICKS:
|
631
618
|
if not self.undetectable:
|
632
|
-
|
619
|
+
with suppress(Exception):
|
633
620
|
self.wait_for_ready_state_complete()
|
634
|
-
except Exception:
|
635
|
-
pass
|
636
621
|
if self.__needs_minimum_wait() or self.browser == "safari":
|
637
622
|
time.sleep(0.05)
|
638
623
|
else:
|
@@ -640,10 +625,8 @@ class BaseCase(unittest.TestCase):
|
|
640
625
|
else:
|
641
626
|
if not self.undetectable:
|
642
627
|
# A smaller subset of self.wait_for_ready_state_complete()
|
643
|
-
|
628
|
+
with suppress(Exception):
|
644
629
|
self.wait_for_angularjs(timeout=settings.MINI_TIMEOUT)
|
645
|
-
except Exception:
|
646
|
-
pass
|
647
630
|
if self.__needs_minimum_wait() or self.browser == "safari":
|
648
631
|
time.sleep(0.045)
|
649
632
|
try:
|
@@ -653,10 +636,8 @@ class BaseCase(unittest.TestCase):
|
|
653
636
|
if self.__needs_minimum_wait():
|
654
637
|
time.sleep(0.075)
|
655
638
|
except Exception:
|
656
|
-
|
639
|
+
with suppress(Exception):
|
657
640
|
self.wait_for_ready_state_complete()
|
658
|
-
except Exception:
|
659
|
-
pass
|
660
641
|
if self.__needs_minimum_wait():
|
661
642
|
time.sleep(0.05)
|
662
643
|
else:
|
@@ -670,6 +651,7 @@ class BaseCase(unittest.TestCase):
|
|
670
651
|
self.__demo_mode_pause_if_active(tiny=True)
|
671
652
|
elif self.slow_mode:
|
672
653
|
self.__slow_mode_pause_if_active()
|
654
|
+
self.__set_esc_skip()
|
673
655
|
|
674
656
|
def slow_click(self, selector, by="css selector", timeout=None):
|
675
657
|
"""Similar to click(), but pauses for a brief moment before clicking.
|
@@ -693,8 +675,6 @@ class BaseCase(unittest.TestCase):
|
|
693
675
|
self.click(selector, by=by, timeout=timeout, delay=0.25)
|
694
676
|
|
695
677
|
def double_click(self, selector, by="css selector", timeout=None):
|
696
|
-
from selenium.webdriver.common.action_chains import ActionChains
|
697
|
-
|
698
678
|
self.__check_scope()
|
699
679
|
if not timeout:
|
700
680
|
timeout = settings.SMALL_TIMEOUT
|
@@ -725,10 +705,8 @@ class BaseCase(unittest.TestCase):
|
|
725
705
|
original_selector=original_selector,
|
726
706
|
)
|
727
707
|
pre_action_url = None
|
728
|
-
|
708
|
+
with suppress(Exception):
|
729
709
|
pre_action_url = self.driver.current_url
|
730
|
-
except Exception:
|
731
|
-
pass
|
732
710
|
try:
|
733
711
|
if self.browser == "safari":
|
734
712
|
# Jump to the "except" block where the other script should work
|
@@ -778,8 +756,6 @@ class BaseCase(unittest.TestCase):
|
|
778
756
|
|
779
757
|
def context_click(self, selector, by="css selector", timeout=None):
|
780
758
|
"""(A context click is a right-click that opens a context menu.)"""
|
781
|
-
from selenium.webdriver.common.action_chains import ActionChains
|
782
|
-
|
783
759
|
self.__check_scope()
|
784
760
|
if not timeout:
|
785
761
|
timeout = settings.SMALL_TIMEOUT
|
@@ -810,10 +786,8 @@ class BaseCase(unittest.TestCase):
|
|
810
786
|
original_selector=original_selector,
|
811
787
|
)
|
812
788
|
pre_action_url = None
|
813
|
-
|
789
|
+
with suppress(Exception):
|
814
790
|
pre_action_url = self.driver.current_url
|
815
|
-
except Exception:
|
816
|
-
pass
|
817
791
|
try:
|
818
792
|
if self.browser == "safari":
|
819
793
|
# Jump to the "except" block where the other script should work
|
@@ -910,6 +884,9 @@ class BaseCase(unittest.TestCase):
|
|
910
884
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
911
885
|
timeout = self.__get_new_timeout(timeout)
|
912
886
|
selector, by = self.__recalculate_selector(selector, by)
|
887
|
+
if self.__is_cdp_swap_needed():
|
888
|
+
self.cdp.type(selector, text, timeout=timeout)
|
889
|
+
return
|
913
890
|
if self.__is_shadow_selector(selector):
|
914
891
|
self.__shadow_type(selector, text, timeout)
|
915
892
|
return
|
@@ -931,19 +908,15 @@ class BaseCase(unittest.TestCase):
|
|
931
908
|
element = self.wait_for_element_clickable(
|
932
909
|
selector, by=by, timeout=timeout
|
933
910
|
)
|
934
|
-
|
911
|
+
with suppress(Exception):
|
935
912
|
element.clear()
|
936
|
-
except Exception:
|
937
|
-
pass # Clearing the text field first might not be necessary
|
938
913
|
except Exception:
|
939
914
|
pass # Clearing the text field first might not be necessary
|
940
915
|
self.__demo_mode_pause_if_active(tiny=True)
|
941
916
|
pre_action_url = None
|
942
917
|
if self.demo_mode:
|
943
|
-
|
918
|
+
with suppress(Exception):
|
944
919
|
pre_action_url = self.driver.current_url
|
945
|
-
except Exception:
|
946
|
-
pass
|
947
920
|
text = self.__get_type_checked_text(text)
|
948
921
|
try:
|
949
922
|
if not text.endswith("\n"):
|
@@ -1027,6 +1000,9 @@ class BaseCase(unittest.TestCase):
|
|
1027
1000
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1028
1001
|
timeout = self.__get_new_timeout(timeout)
|
1029
1002
|
selector, by = self.__recalculate_selector(selector, by)
|
1003
|
+
if self.__is_cdp_swap_needed():
|
1004
|
+
self.cdp.send_keys(selector, text)
|
1005
|
+
return
|
1030
1006
|
if self.__is_shadow_selector(selector):
|
1031
1007
|
self.__shadow_type(selector, text, timeout, clear_first=False)
|
1032
1008
|
return
|
@@ -1053,10 +1029,8 @@ class BaseCase(unittest.TestCase):
|
|
1053
1029
|
self.__scroll_to_element(element, selector, by)
|
1054
1030
|
pre_action_url = None
|
1055
1031
|
if self.demo_mode:
|
1056
|
-
|
1032
|
+
with suppress(Exception):
|
1057
1033
|
pre_action_url = self.driver.current_url
|
1058
|
-
except Exception:
|
1059
|
-
pass
|
1060
1034
|
text = self.__get_type_checked_text(text)
|
1061
1035
|
try:
|
1062
1036
|
if not text.endswith("\n"):
|
@@ -1137,6 +1111,9 @@ class BaseCase(unittest.TestCase):
|
|
1137
1111
|
|
1138
1112
|
def press_keys(self, selector, text, by="css selector", timeout=None):
|
1139
1113
|
"""Use send_keys() to press one key at a time."""
|
1114
|
+
if self.__is_cdp_swap_needed():
|
1115
|
+
self.cdp.press_keys(selector, text, timeout=timeout)
|
1116
|
+
return
|
1140
1117
|
self.wait_for_ready_state_complete()
|
1141
1118
|
element = self.wait_for_element_present(
|
1142
1119
|
selector, by=by, timeout=timeout
|
@@ -1229,11 +1206,9 @@ class BaseCase(unittest.TestCase):
|
|
1229
1206
|
selector, by=by, timeout=timeout
|
1230
1207
|
)
|
1231
1208
|
element.clear()
|
1232
|
-
|
1209
|
+
with suppress(Exception):
|
1233
1210
|
backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
|
1234
1211
|
element.send_keys(backspaces)
|
1235
|
-
except Exception:
|
1236
|
-
pass
|
1237
1212
|
except Exception:
|
1238
1213
|
element.clear()
|
1239
1214
|
|
@@ -1247,9 +1222,20 @@ class BaseCase(unittest.TestCase):
|
|
1247
1222
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1248
1223
|
timeout = self.__get_new_timeout(timeout)
|
1249
1224
|
selector, by = self.__recalculate_selector(selector, by)
|
1250
|
-
|
1225
|
+
if self.__is_cdp_swap_needed():
|
1226
|
+
self.cdp.focus(selector)
|
1227
|
+
return
|
1228
|
+
element = self.wait_for_element_present(
|
1251
1229
|
selector, by=by, timeout=timeout
|
1252
1230
|
)
|
1231
|
+
if not element.is_displayed():
|
1232
|
+
css_selector = self.convert_to_css_selector(selector, by=by)
|
1233
|
+
css_selector = re.escape(css_selector) # Add "\\" to special chars
|
1234
|
+
css_selector = self.__escape_quotes_if_needed(css_selector)
|
1235
|
+
script = """document.querySelector('%s').focus();""" % css_selector
|
1236
|
+
self.execute_script(script)
|
1237
|
+
self.__demo_mode_pause_if_active()
|
1238
|
+
return
|
1253
1239
|
self.scroll_to(selector, by=by, timeout=timeout)
|
1254
1240
|
try:
|
1255
1241
|
element.send_keys(Keys.NULL)
|
@@ -1269,6 +1255,9 @@ class BaseCase(unittest.TestCase):
|
|
1269
1255
|
def refresh_page(self):
|
1270
1256
|
self.__check_scope()
|
1271
1257
|
self.__last_page_load_url = None
|
1258
|
+
if self.__is_cdp_swap_needed():
|
1259
|
+
self.cdp.reload()
|
1260
|
+
return
|
1272
1261
|
js_utils.clear_out_console_logs(self.driver)
|
1273
1262
|
self.driver.refresh()
|
1274
1263
|
self.wait_for_ready_state_complete()
|
@@ -1279,7 +1268,11 @@ class BaseCase(unittest.TestCase):
|
|
1279
1268
|
|
1280
1269
|
def get_current_url(self):
|
1281
1270
|
self.__check_scope()
|
1282
|
-
current_url =
|
1271
|
+
current_url = None
|
1272
|
+
if self.__is_cdp_swap_needed():
|
1273
|
+
current_url = self.cdp.get_current_url()
|
1274
|
+
else:
|
1275
|
+
current_url = self.driver.current_url
|
1283
1276
|
if "%" in current_url:
|
1284
1277
|
try:
|
1285
1278
|
from urllib.parse import unquote
|
@@ -1294,15 +1287,22 @@ class BaseCase(unittest.TestCase):
|
|
1294
1287
|
return self.execute_script("return window.location.origin;")
|
1295
1288
|
|
1296
1289
|
def get_page_source(self):
|
1290
|
+
if self.__is_cdp_swap_needed():
|
1291
|
+
return self.cdp.get_page_source()
|
1297
1292
|
self.wait_for_ready_state_complete()
|
1298
1293
|
if self.__needs_minimum_wait:
|
1299
|
-
time.sleep(0.
|
1294
|
+
time.sleep(0.025)
|
1300
1295
|
return self.driver.page_source
|
1301
1296
|
|
1302
1297
|
def get_page_title(self):
|
1298
|
+
if self.__is_cdp_swap_needed():
|
1299
|
+
return self.cdp.get_title()
|
1303
1300
|
self.wait_for_ready_state_complete()
|
1304
|
-
|
1305
|
-
|
1301
|
+
with suppress(Exception):
|
1302
|
+
self.wait_for_element_present(
|
1303
|
+
"title", by="css selector", timeout=settings.MINI_TIMEOUT
|
1304
|
+
)
|
1305
|
+
time.sleep(0.025)
|
1306
1306
|
return self.driver.title
|
1307
1307
|
|
1308
1308
|
def get_title(self):
|
@@ -1310,31 +1310,32 @@ class BaseCase(unittest.TestCase):
|
|
1310
1310
|
return self.get_page_title()
|
1311
1311
|
|
1312
1312
|
def get_user_agent(self):
|
1313
|
-
|
1314
|
-
|
1313
|
+
if self.__is_cdp_swap_needed():
|
1314
|
+
return self.cdp.get_user_agent()
|
1315
|
+
return self.execute_script("return navigator.userAgent;")
|
1315
1316
|
|
1316
1317
|
def get_locale_code(self):
|
1317
|
-
|
1318
|
+
if self.__is_cdp_swap_needed():
|
1319
|
+
return self.cdp.get_locale_code()
|
1320
|
+
return self.execute_script(
|
1318
1321
|
"return navigator.language || navigator.languages[0];"
|
1319
1322
|
)
|
1320
|
-
return locale_code
|
1321
1323
|
|
1322
1324
|
def go_back(self):
|
1323
1325
|
self.__check_scope()
|
1326
|
+
if self.__is_cdp_swap_needed():
|
1327
|
+
self.cdp.go_back()
|
1328
|
+
return
|
1324
1329
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
1325
1330
|
self.save_recorded_actions()
|
1326
1331
|
pre_action_url = None
|
1327
|
-
|
1332
|
+
with suppress(Exception):
|
1328
1333
|
pre_action_url = self.driver.current_url
|
1329
|
-
except Exception:
|
1330
|
-
pass
|
1331
1334
|
self.__last_page_load_url = None
|
1332
1335
|
self.driver.back()
|
1333
|
-
|
1336
|
+
with suppress(Exception):
|
1334
1337
|
if pre_action_url == self.driver.current_url:
|
1335
1338
|
self.driver.back() # Again because the page was redirected
|
1336
|
-
except Exception:
|
1337
|
-
pass
|
1338
1339
|
if self.recorder_mode:
|
1339
1340
|
time_stamp = self.execute_script("return Date.now();")
|
1340
1341
|
origin = self.get_origin()
|
@@ -1350,6 +1351,9 @@ class BaseCase(unittest.TestCase):
|
|
1350
1351
|
|
1351
1352
|
def go_forward(self):
|
1352
1353
|
self.__check_scope()
|
1354
|
+
if self.__is_cdp_swap_needed():
|
1355
|
+
self.cdp.go_forward()
|
1356
|
+
return
|
1353
1357
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
1354
1358
|
self.save_recorded_actions()
|
1355
1359
|
self.__last_page_load_url = None
|
@@ -1403,7 +1407,7 @@ class BaseCase(unittest.TestCase):
|
|
1403
1407
|
to convert the open() action into open_if_not_url() so that the
|
1404
1408
|
same page isn't opened again if the user is already on the page."""
|
1405
1409
|
self.__check_scope()
|
1406
|
-
current_url = self.
|
1410
|
+
current_url = self.get_current_url()
|
1407
1411
|
if current_url != url:
|
1408
1412
|
if (
|
1409
1413
|
"?q=" not in current_url
|
@@ -1414,6 +1418,9 @@ class BaseCase(unittest.TestCase):
|
|
1414
1418
|
self.open(url)
|
1415
1419
|
|
1416
1420
|
def is_element_present(self, selector, by="css selector"):
|
1421
|
+
"""Returns whether the element exists in the HTML."""
|
1422
|
+
if self.__is_cdp_swap_needed():
|
1423
|
+
return self.cdp.is_element_present(selector)
|
1417
1424
|
self.wait_for_ready_state_complete()
|
1418
1425
|
selector, by = self.__recalculate_selector(selector, by)
|
1419
1426
|
if self.__is_shadow_selector(selector):
|
@@ -1421,6 +1428,9 @@ class BaseCase(unittest.TestCase):
|
|
1421
1428
|
return page_actions.is_element_present(self.driver, selector, by)
|
1422
1429
|
|
1423
1430
|
def is_element_visible(self, selector, by="css selector"):
|
1431
|
+
"""Returns whether the element is visible on the page."""
|
1432
|
+
if self.__is_cdp_swap_needed():
|
1433
|
+
return self.cdp.is_element_visible(selector)
|
1424
1434
|
self.wait_for_ready_state_complete()
|
1425
1435
|
selector, by = self.__recalculate_selector(selector, by)
|
1426
1436
|
if self.__is_shadow_selector(selector):
|
@@ -1441,7 +1451,8 @@ class BaseCase(unittest.TestCase):
|
|
1441
1451
|
return self.__is_shadow_element_enabled(selector)
|
1442
1452
|
return page_actions.is_element_enabled(self.driver, selector, by)
|
1443
1453
|
|
1444
|
-
def is_text_visible(self, text, selector="
|
1454
|
+
def is_text_visible(self, text, selector="body", by="css selector"):
|
1455
|
+
"""Returns whether the text substring is visible in the element."""
|
1445
1456
|
self.wait_for_ready_state_complete()
|
1446
1457
|
time.sleep(0.01)
|
1447
1458
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -1449,7 +1460,9 @@ class BaseCase(unittest.TestCase):
|
|
1449
1460
|
return self.__is_shadow_text_visible(text, selector)
|
1450
1461
|
return page_actions.is_text_visible(self.driver, text, selector, by)
|
1451
1462
|
|
1452
|
-
def is_exact_text_visible(self, text, selector="
|
1463
|
+
def is_exact_text_visible(self, text, selector="body", by="css selector"):
|
1464
|
+
"""Returns whether the text is exactly equal to the element text.
|
1465
|
+
(Leading and trailing whitespace is ignored in the verification.)"""
|
1453
1466
|
self.wait_for_ready_state_complete()
|
1454
1467
|
time.sleep(0.01)
|
1455
1468
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -1459,7 +1472,7 @@ class BaseCase(unittest.TestCase):
|
|
1459
1472
|
self.driver, text, selector, by
|
1460
1473
|
)
|
1461
1474
|
|
1462
|
-
def is_non_empty_text_visible(self, selector="
|
1475
|
+
def is_non_empty_text_visible(self, selector="body", by="css selector"):
|
1463
1476
|
"""Returns whether the element has any non-empty text visible.
|
1464
1477
|
Whitespace-only text is considered empty text."""
|
1465
1478
|
self.wait_for_ready_state_complete()
|
@@ -1488,6 +1501,7 @@ class BaseCase(unittest.TestCase):
|
|
1488
1501
|
)
|
1489
1502
|
|
1490
1503
|
def is_link_text_visible(self, link_text):
|
1504
|
+
"""Returns whether there's an exact match for the link text."""
|
1491
1505
|
self.wait_for_ready_state_complete()
|
1492
1506
|
time.sleep(0.01)
|
1493
1507
|
return page_actions.is_element_visible(
|
@@ -1495,6 +1509,7 @@ class BaseCase(unittest.TestCase):
|
|
1495
1509
|
)
|
1496
1510
|
|
1497
1511
|
def is_partial_link_text_visible(self, partial_link_text):
|
1512
|
+
"""Returns whether there's a substring match for the link text."""
|
1498
1513
|
self.wait_for_ready_state_complete()
|
1499
1514
|
time.sleep(0.01)
|
1500
1515
|
return page_actions.is_element_visible(
|
@@ -1587,11 +1602,18 @@ class BaseCase(unittest.TestCase):
|
|
1587
1602
|
def click_link_text(self, link_text, timeout=None):
|
1588
1603
|
"""This method clicks link text on a page."""
|
1589
1604
|
self.__check_scope()
|
1605
|
+
if self.__is_cdp_swap_needed():
|
1606
|
+
self.cdp.find_element(link_text, timeout=timeout).click()
|
1607
|
+
return
|
1608
|
+
self.__skip_if_esc()
|
1590
1609
|
if not timeout:
|
1591
1610
|
timeout = settings.SMALL_TIMEOUT
|
1592
1611
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
1593
1612
|
timeout = self.__get_new_timeout(timeout)
|
1594
1613
|
link_text = self.__get_type_checked_text(link_text)
|
1614
|
+
if self.__is_cdp_swap_needed():
|
1615
|
+
self.cdp.click_link(link_text)
|
1616
|
+
return
|
1595
1617
|
if self.browser == "safari":
|
1596
1618
|
if self.demo_mode:
|
1597
1619
|
self.wait_for_link_text_present(link_text, timeout=timeout)
|
@@ -1622,10 +1644,8 @@ class BaseCase(unittest.TestCase):
|
|
1622
1644
|
if self.__needs_minimum_wait():
|
1623
1645
|
time.sleep(0.04)
|
1624
1646
|
pre_action_url = None
|
1625
|
-
|
1647
|
+
with suppress(Exception):
|
1626
1648
|
pre_action_url = self.driver.current_url
|
1627
|
-
except Exception:
|
1628
|
-
pass
|
1629
1649
|
pre_window_count = len(self.driver.window_handles)
|
1630
1650
|
try:
|
1631
1651
|
element = self.wait_for_link_text_visible(link_text, timeout=0.2)
|
@@ -1696,10 +1716,8 @@ class BaseCase(unittest.TestCase):
|
|
1696
1716
|
# switch to the last one if it exists.
|
1697
1717
|
self.switch_to_window(-1)
|
1698
1718
|
if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
|
1699
|
-
|
1719
|
+
with suppress(Exception):
|
1700
1720
|
self.wait_for_ready_state_complete()
|
1701
|
-
except Exception:
|
1702
|
-
pass
|
1703
1721
|
if self.demo_mode:
|
1704
1722
|
if self.driver.current_url != pre_action_url:
|
1705
1723
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -1720,15 +1738,16 @@ class BaseCase(unittest.TestCase):
|
|
1720
1738
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
1721
1739
|
timeout = self.__get_new_timeout(timeout)
|
1722
1740
|
partial_link_text = self.__get_type_checked_text(partial_link_text)
|
1741
|
+
if self.__is_cdp_swap_needed():
|
1742
|
+
self.cdp.find_element(partial_link_text, timeout=timeout).click()
|
1743
|
+
return
|
1723
1744
|
if not self.is_partial_link_text_present(partial_link_text):
|
1724
1745
|
self.wait_for_partial_link_text_present(
|
1725
1746
|
partial_link_text, timeout=timeout
|
1726
1747
|
)
|
1727
1748
|
pre_action_url = None
|
1728
|
-
|
1749
|
+
with suppress(Exception):
|
1729
1750
|
pre_action_url = self.driver.current_url
|
1730
|
-
except Exception:
|
1731
|
-
pass
|
1732
1751
|
pre_window_count = len(self.driver.window_handles)
|
1733
1752
|
try:
|
1734
1753
|
element = self.wait_for_partial_link_text(
|
@@ -1811,10 +1830,8 @@ class BaseCase(unittest.TestCase):
|
|
1811
1830
|
# switch to the last one if it exists.
|
1812
1831
|
self.switch_to_window(-1)
|
1813
1832
|
if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
|
1814
|
-
|
1833
|
+
with suppress(Exception):
|
1815
1834
|
self.wait_for_ready_state_complete()
|
1816
|
-
except Exception:
|
1817
|
-
pass
|
1818
1835
|
if self.demo_mode:
|
1819
1836
|
if self.driver.current_url != pre_action_url:
|
1820
1837
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -1825,13 +1842,15 @@ class BaseCase(unittest.TestCase):
|
|
1825
1842
|
elif self.slow_mode:
|
1826
1843
|
self.__slow_mode_pause_if_active()
|
1827
1844
|
|
1828
|
-
def get_text(self, selector, by="css selector", timeout=None):
|
1845
|
+
def get_text(self, selector="body", by="css selector", timeout=None):
|
1829
1846
|
self.__check_scope()
|
1830
1847
|
if not timeout:
|
1831
1848
|
timeout = settings.LARGE_TIMEOUT
|
1832
1849
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1833
1850
|
timeout = self.__get_new_timeout(timeout)
|
1834
1851
|
selector, by = self.__recalculate_selector(selector, by)
|
1852
|
+
if self.__is_cdp_swap_needed():
|
1853
|
+
return self.cdp.get_text(selector)
|
1835
1854
|
if self.__is_shadow_selector(selector):
|
1836
1855
|
return self.__get_shadow_text(selector, timeout)
|
1837
1856
|
self.wait_for_ready_state_complete()
|
@@ -1881,6 +1900,8 @@ class BaseCase(unittest.TestCase):
|
|
1881
1900
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1882
1901
|
timeout = self.__get_new_timeout(timeout)
|
1883
1902
|
selector, by = self.__recalculate_selector(selector, by)
|
1903
|
+
if self.__is_cdp_swap_needed():
|
1904
|
+
return self.cdp.get_element_attribute(selector, attribute)
|
1884
1905
|
self.wait_for_ready_state_complete()
|
1885
1906
|
time.sleep(0.01)
|
1886
1907
|
if self.__is_shadow_selector(selector):
|
@@ -1930,10 +1951,8 @@ class BaseCase(unittest.TestCase):
|
|
1930
1951
|
original_attribute = attribute
|
1931
1952
|
original_value = value
|
1932
1953
|
if scroll and self.is_element_visible(selector, by=by):
|
1933
|
-
|
1954
|
+
with suppress(Exception):
|
1934
1955
|
self.scroll_to(selector, by=by, timeout=timeout)
|
1935
|
-
except Exception:
|
1936
|
-
pass
|
1937
1956
|
attribute = re.escape(attribute)
|
1938
1957
|
attribute = self.__escape_quotes_if_needed(attribute)
|
1939
1958
|
value = re.escape(value)
|
@@ -1961,6 +1980,9 @@ class BaseCase(unittest.TestCase):
|
|
1961
1980
|
self.set_attributes("a", "href", "https://google.com")"""
|
1962
1981
|
self.__check_scope()
|
1963
1982
|
selector, by = self.__recalculate_selector(selector, by)
|
1983
|
+
if self.__is_cdp_swap_needed():
|
1984
|
+
self.cdp.set_attributes(selector, attribute, value)
|
1985
|
+
return
|
1964
1986
|
original_attribute = attribute
|
1965
1987
|
original_value = value
|
1966
1988
|
attribute = re.escape(attribute)
|
@@ -1978,10 +2000,8 @@ class BaseCase(unittest.TestCase):
|
|
1978
2000
|
attribute,
|
1979
2001
|
value,
|
1980
2002
|
)
|
1981
|
-
|
2003
|
+
with suppress(Exception):
|
1982
2004
|
self.execute_script(script)
|
1983
|
-
except Exception:
|
1984
|
-
pass
|
1985
2005
|
if self.recorder_mode and self.__current_url_is_recordable():
|
1986
2006
|
if self.get_session_storage_item("pause_recorder") == "no":
|
1987
2007
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -2010,10 +2030,8 @@ class BaseCase(unittest.TestCase):
|
|
2010
2030
|
timeout = self.__get_new_timeout(timeout)
|
2011
2031
|
selector, by = self.__recalculate_selector(selector, by)
|
2012
2032
|
if self.is_element_visible(selector, by=by):
|
2013
|
-
|
2033
|
+
with suppress(Exception):
|
2014
2034
|
self.scroll_to(selector, by=by, timeout=timeout)
|
2015
|
-
except Exception:
|
2016
|
-
pass
|
2017
2035
|
attribute = re.escape(attribute)
|
2018
2036
|
attribute = self.__escape_quotes_if_needed(attribute)
|
2019
2037
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
@@ -2042,10 +2060,16 @@ class BaseCase(unittest.TestCase):
|
|
2042
2060
|
css_selector,
|
2043
2061
|
attribute,
|
2044
2062
|
)
|
2045
|
-
|
2063
|
+
with suppress(Exception):
|
2046
2064
|
self.execute_script(script)
|
2047
|
-
|
2048
|
-
|
2065
|
+
|
2066
|
+
def internalize_links(self):
|
2067
|
+
"""All `target="_blank"` links become `target="_self"`.
|
2068
|
+
This prevents those links from opening in a new tab."""
|
2069
|
+
if self.__is_cdp_swap_needed():
|
2070
|
+
self.cdp.internalize_links()
|
2071
|
+
return
|
2072
|
+
self.set_attributes('[target="_blank"]', "target", "_self")
|
2049
2073
|
|
2050
2074
|
def get_property(
|
2051
2075
|
self, selector, property, by="css selector", timeout=None
|
@@ -2080,7 +2104,9 @@ class BaseCase(unittest.TestCase):
|
|
2080
2104
|
return ""
|
2081
2105
|
return property_value
|
2082
2106
|
|
2083
|
-
def get_text_content(
|
2107
|
+
def get_text_content(
|
2108
|
+
self, selector="body", by="css selector", timeout=None
|
2109
|
+
):
|
2084
2110
|
"""Returns the text that appears in the HTML for an element.
|
2085
2111
|
This is different from "self.get_text(selector, by="css selector")"
|
2086
2112
|
because that only returns the visible text on a page for an element,
|
@@ -2148,6 +2174,11 @@ class BaseCase(unittest.TestCase):
|
|
2148
2174
|
Elements could be either hidden or visible on the page.
|
2149
2175
|
If "limit" is set and > 0, will only return that many elements."""
|
2150
2176
|
selector, by = self.__recalculate_selector(selector, by)
|
2177
|
+
if self.__is_cdp_swap_needed():
|
2178
|
+
elements = self.cdp.select_all(selector)
|
2179
|
+
if limit and limit > 0 and len(elements) > limit:
|
2180
|
+
elements = elements[:limit]
|
2181
|
+
return elements
|
2151
2182
|
self.wait_for_ready_state_complete()
|
2152
2183
|
time.sleep(0.05)
|
2153
2184
|
elements = self.driver.find_elements(by=by, value=selector)
|
@@ -2159,12 +2190,16 @@ class BaseCase(unittest.TestCase):
|
|
2159
2190
|
"""Returns a list of matching WebElements that are visible.
|
2160
2191
|
If "limit" is set and > 0, will only return that many elements."""
|
2161
2192
|
selector, by = self.__recalculate_selector(selector, by)
|
2193
|
+
if self.__is_cdp_swap_needed():
|
2194
|
+
elements = self.cdp.find_visible_elements(selector)
|
2195
|
+
if limit and limit > 0 and len(elements) > limit:
|
2196
|
+
elements = elements[:limit]
|
2197
|
+
return elements
|
2162
2198
|
self.wait_for_ready_state_complete()
|
2163
2199
|
time.sleep(0.05)
|
2164
|
-
|
2200
|
+
return page_actions.find_visible_elements(
|
2165
2201
|
self.driver, selector, by, limit
|
2166
2202
|
)
|
2167
|
-
return v_elems
|
2168
2203
|
|
2169
2204
|
def click_visible_elements(
|
2170
2205
|
self, selector, by="css selector", limit=0, timeout=None
|
@@ -2182,6 +2217,9 @@ class BaseCase(unittest.TestCase):
|
|
2182
2217
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2183
2218
|
timeout = self.__get_new_timeout(timeout)
|
2184
2219
|
selector, by = self.__recalculate_selector(selector, by)
|
2220
|
+
if self.__is_cdp_swap_needed():
|
2221
|
+
self.cdp.click_visible_elements(selector, limit)
|
2222
|
+
return
|
2185
2223
|
self.wait_for_ready_state_complete()
|
2186
2224
|
if self.__needs_minimum_wait():
|
2187
2225
|
time.sleep(0.12)
|
@@ -2190,20 +2228,16 @@ class BaseCase(unittest.TestCase):
|
|
2190
2228
|
element = self.wait_for_element_present(
|
2191
2229
|
selector, by=by, timeout=timeout
|
2192
2230
|
)
|
2193
|
-
|
2231
|
+
with suppress(Exception):
|
2194
2232
|
# If the first element isn't visible, wait a little.
|
2195
2233
|
if not element.is_displayed():
|
2196
2234
|
time.sleep(0.16)
|
2197
2235
|
if self.undetectable:
|
2198
2236
|
time.sleep(0.06)
|
2199
|
-
except Exception:
|
2200
|
-
pass
|
2201
2237
|
elements = self.find_elements(selector, by=by)
|
2202
2238
|
pre_action_url = None
|
2203
|
-
|
2239
|
+
with suppress(Exception):
|
2204
2240
|
pre_action_url = self.driver.current_url
|
2205
|
-
except Exception:
|
2206
|
-
pass
|
2207
2241
|
pre_window_count = len(self.driver.window_handles)
|
2208
2242
|
click_count = 0
|
2209
2243
|
for element in elements:
|
@@ -2266,13 +2300,16 @@ class BaseCase(unittest.TestCase):
|
|
2266
2300
|
):
|
2267
2301
|
"""Finds all matching page elements and clicks the nth visible one.
|
2268
2302
|
Example: self.click_nth_visible_element('[type="checkbox"]', 5)
|
2269
|
-
|
2303
|
+
(Clicks the 5th visible checkbox on the page.)"""
|
2270
2304
|
self.__check_scope()
|
2271
2305
|
if not timeout:
|
2272
2306
|
timeout = settings.SMALL_TIMEOUT
|
2273
2307
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2274
2308
|
timeout = self.__get_new_timeout(timeout)
|
2275
2309
|
selector, by = self.__recalculate_selector(selector, by)
|
2310
|
+
if self.__is_cdp_swap_needed():
|
2311
|
+
self.cdp.click_nth_visible_element(selector, number)
|
2312
|
+
return
|
2276
2313
|
self.wait_for_ready_state_complete()
|
2277
2314
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
2278
2315
|
elements = self.find_visible_elements(selector, by=by)
|
@@ -2286,10 +2323,8 @@ class BaseCase(unittest.TestCase):
|
|
2286
2323
|
number = 0
|
2287
2324
|
element = elements[number]
|
2288
2325
|
pre_action_url = None
|
2289
|
-
|
2326
|
+
with suppress(Exception):
|
2290
2327
|
pre_action_url = self.driver.current_url
|
2291
|
-
except Exception:
|
2292
|
-
pass
|
2293
2328
|
pre_window_count = len(self.driver.window_handles)
|
2294
2329
|
try:
|
2295
2330
|
self.__scroll_to_element(element)
|
@@ -2328,26 +2363,28 @@ class BaseCase(unittest.TestCase):
|
|
2328
2363
|
Use click_visible_elements() to click all matching elements.
|
2329
2364
|
If a "timeout" is provided, waits that long for the element
|
2330
2365
|
to appear before giving up and returning without a click()."""
|
2366
|
+
if self.__is_cdp_swap_needed():
|
2367
|
+
self.cdp.click_if_visible(selector)
|
2368
|
+
return
|
2331
2369
|
self.wait_for_ready_state_complete()
|
2332
2370
|
if self.is_element_visible(selector, by=by):
|
2333
2371
|
self.click(selector, by=by)
|
2334
2372
|
elif timeout > 0:
|
2335
|
-
|
2373
|
+
with suppress(Exception):
|
2336
2374
|
self.wait_for_element_visible(
|
2337
2375
|
selector, by=by, timeout=timeout
|
2338
2376
|
)
|
2339
|
-
except Exception:
|
2340
|
-
pass
|
2341
2377
|
if self.is_element_visible(selector, by=by):
|
2342
2378
|
self.click(selector, by=by)
|
2343
2379
|
|
2344
2380
|
def click_active_element(self):
|
2381
|
+
if self.__is_cdp_swap_needed():
|
2382
|
+
self.cdp.click_active_element()
|
2383
|
+
return
|
2345
2384
|
self.wait_for_ready_state_complete()
|
2346
2385
|
pre_action_url = None
|
2347
|
-
|
2386
|
+
with suppress(Exception):
|
2348
2387
|
pre_action_url = self.driver.current_url
|
2349
|
-
except Exception:
|
2350
|
-
pass
|
2351
2388
|
pre_window_count = len(self.driver.window_handles)
|
2352
2389
|
if self.recorder_mode:
|
2353
2390
|
selector = js_utils.get_active_element_css(self.driver)
|
@@ -2451,16 +2488,14 @@ class BaseCase(unittest.TestCase):
|
|
2451
2488
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2452
2489
|
timeout = self.__get_new_timeout(timeout)
|
2453
2490
|
selector, by = self.__recalculate_selector(selector, by)
|
2491
|
+
if self.__is_cdp_swap_needed():
|
2492
|
+
return self.cdp.is_checked(selector)
|
2454
2493
|
kind = self.get_attribute(selector, "type", by=by, timeout=timeout)
|
2455
2494
|
if kind != "checkbox" and kind != "radio":
|
2456
2495
|
raise Exception("Expecting a checkbox or a radio button element!")
|
2457
|
-
|
2496
|
+
return self.get_attribute(
|
2458
2497
|
selector, "checked", by=by, timeout=timeout, hard_fail=False
|
2459
2498
|
)
|
2460
|
-
if is_checked:
|
2461
|
-
return True
|
2462
|
-
else: # (NoneType)
|
2463
|
-
return False
|
2464
2499
|
|
2465
2500
|
def is_selected(self, selector, by="css selector", timeout=None):
|
2466
2501
|
"""Same as is_checked()"""
|
@@ -2470,6 +2505,9 @@ class BaseCase(unittest.TestCase):
|
|
2470
2505
|
"""If a checkbox or radio button is not checked, will check it."""
|
2471
2506
|
self.__check_scope()
|
2472
2507
|
selector, by = self.__recalculate_selector(selector, by)
|
2508
|
+
if self.__is_cdp_swap_needed():
|
2509
|
+
self.cdp.check_if_unchecked(selector)
|
2510
|
+
return
|
2473
2511
|
if not self.is_checked(selector, by=by):
|
2474
2512
|
if self.is_element_visible(selector, by=by):
|
2475
2513
|
self.click(selector, by=by)
|
@@ -2480,12 +2518,10 @@ class BaseCase(unittest.TestCase):
|
|
2480
2518
|
)
|
2481
2519
|
# Handle switches that sit on checkboxes with zero opacity:
|
2482
2520
|
# Change the opacity a bit to allow the click to succeed.
|
2483
|
-
|
2521
|
+
with suppress(Exception):
|
2484
2522
|
self.execute_script(
|
2485
2523
|
'arguments[0].style.opacity="0.001";', element
|
2486
2524
|
)
|
2487
|
-
except Exception:
|
2488
|
-
pass
|
2489
2525
|
if self.is_element_visible(selector, by=by):
|
2490
2526
|
self.click(selector, by=by)
|
2491
2527
|
else:
|
@@ -2493,14 +2529,12 @@ class BaseCase(unittest.TestCase):
|
|
2493
2529
|
self.__dont_record_js_click = True
|
2494
2530
|
self.js_click(selector, by="css selector")
|
2495
2531
|
self.__dont_record_js_click = False
|
2496
|
-
|
2532
|
+
with suppress(Exception):
|
2497
2533
|
self.execute_script(
|
2498
2534
|
'arguments[0].style.opacity="arguments[1]";',
|
2499
2535
|
element,
|
2500
2536
|
opacity,
|
2501
2537
|
)
|
2502
|
-
except Exception:
|
2503
|
-
pass
|
2504
2538
|
|
2505
2539
|
def select_if_unselected(self, selector, by="css selector"):
|
2506
2540
|
"""Same as check_if_unchecked()"""
|
@@ -2510,6 +2544,9 @@ class BaseCase(unittest.TestCase):
|
|
2510
2544
|
"""If a checkbox is checked, will uncheck it."""
|
2511
2545
|
self.__check_scope()
|
2512
2546
|
selector, by = self.__recalculate_selector(selector, by)
|
2547
|
+
if self.__is_cdp_swap_needed():
|
2548
|
+
self.cdp.uncheck_if_checked(selector)
|
2549
|
+
return
|
2513
2550
|
if self.is_checked(selector, by=by):
|
2514
2551
|
if self.is_element_visible(selector, by=by):
|
2515
2552
|
self.click(selector, by=by)
|
@@ -2520,12 +2557,10 @@ class BaseCase(unittest.TestCase):
|
|
2520
2557
|
)
|
2521
2558
|
# Handle switches that sit on checkboxes with zero opacity:
|
2522
2559
|
# Change the opacity a bit to allow the click to succeed.
|
2523
|
-
|
2560
|
+
with suppress(Exception):
|
2524
2561
|
self.execute_script(
|
2525
2562
|
'arguments[0].style.opacity="0.001";', element
|
2526
2563
|
)
|
2527
|
-
except Exception:
|
2528
|
-
pass
|
2529
2564
|
if self.is_element_visible(selector, by=by):
|
2530
2565
|
self.click(selector, by=by)
|
2531
2566
|
else:
|
@@ -2533,14 +2568,12 @@ class BaseCase(unittest.TestCase):
|
|
2533
2568
|
self.__dont_record_js_click = True
|
2534
2569
|
self.js_click(selector, by="css selector")
|
2535
2570
|
self.__dont_record_js_click = False
|
2536
|
-
|
2571
|
+
with suppress(Exception):
|
2537
2572
|
self.execute_script(
|
2538
2573
|
'arguments[0].style.opacity="arguments[1]";',
|
2539
2574
|
element,
|
2540
2575
|
opacity,
|
2541
2576
|
)
|
2542
|
-
except Exception:
|
2543
|
-
pass
|
2544
2577
|
|
2545
2578
|
def unselect_if_selected(self, selector, by="css selector"):
|
2546
2579
|
"""Same as uncheck_if_checked()"""
|
@@ -2599,14 +2632,12 @@ class BaseCase(unittest.TestCase):
|
|
2599
2632
|
iframe_identifier = '[class="%s"]' % iframe_class
|
2600
2633
|
else:
|
2601
2634
|
continue
|
2602
|
-
|
2635
|
+
with suppress(Exception):
|
2603
2636
|
self.switch_to_frame(iframe_identifier, timeout=1)
|
2604
2637
|
if self.__needs_minimum_wait():
|
2605
2638
|
time.sleep(0.02)
|
2606
2639
|
if self.is_element_present(selector, by=by):
|
2607
2640
|
return iframe_identifier
|
2608
|
-
except Exception:
|
2609
|
-
pass
|
2610
2641
|
self.switch_to_default_content()
|
2611
2642
|
if self.__needs_minimum_wait():
|
2612
2643
|
time.sleep(0.02)
|
@@ -2632,6 +2663,9 @@ class BaseCase(unittest.TestCase):
|
|
2632
2663
|
original_selector = selector
|
2633
2664
|
original_by = by
|
2634
2665
|
selector, by = self.__recalculate_selector(selector, by)
|
2666
|
+
if self.__is_cdp_swap_needed():
|
2667
|
+
self.cdp.gui_hover_element(selector)
|
2668
|
+
return
|
2635
2669
|
self.wait_for_element_visible(
|
2636
2670
|
original_selector, by=original_by, timeout=timeout
|
2637
2671
|
)
|
@@ -2674,16 +2708,17 @@ class BaseCase(unittest.TestCase):
|
|
2674
2708
|
click_selector, click_by = self.__recalculate_selector(
|
2675
2709
|
click_selector, click_by
|
2676
2710
|
)
|
2711
|
+
if self.__is_cdp_swap_needed():
|
2712
|
+
self.cdp.gui_hover_and_click(hover_selector, click_selector)
|
2713
|
+
return
|
2677
2714
|
dropdown_element = self.wait_for_element_visible(
|
2678
2715
|
original_selector, by=original_by, timeout=timeout
|
2679
2716
|
)
|
2680
2717
|
self.__demo_mode_highlight_if_active(original_selector, original_by)
|
2681
2718
|
self.scroll_to(hover_selector, by=hover_by)
|
2682
2719
|
pre_action_url = None
|
2683
|
-
|
2720
|
+
with suppress(Exception):
|
2684
2721
|
pre_action_url = self.driver.current_url
|
2685
|
-
except Exception:
|
2686
|
-
pass
|
2687
2722
|
pre_window_count = len(self.driver.window_handles)
|
2688
2723
|
if self.recorder_mode and self.__current_url_is_recordable():
|
2689
2724
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -2747,10 +2782,8 @@ class BaseCase(unittest.TestCase):
|
|
2747
2782
|
self.__switch_to_newest_window_if_not_blank()
|
2748
2783
|
elif self.browser == "safari":
|
2749
2784
|
# Release the hover by hovering elsewhere
|
2750
|
-
|
2785
|
+
with suppress(Exception):
|
2751
2786
|
page_actions.hover_on_element(self.driver, "body")
|
2752
|
-
except Exception:
|
2753
|
-
pass
|
2754
2787
|
if self.demo_mode:
|
2755
2788
|
if self.driver.current_url != pre_action_url:
|
2756
2789
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -2810,10 +2843,8 @@ class BaseCase(unittest.TestCase):
|
|
2810
2843
|
self.__demo_mode_highlight_if_active(original_selector, original_by)
|
2811
2844
|
self.scroll_to(hover_selector, by=hover_by)
|
2812
2845
|
pre_action_url = None
|
2813
|
-
|
2846
|
+
with suppress(Exception):
|
2814
2847
|
pre_action_url = self.driver.current_url
|
2815
|
-
except Exception:
|
2816
|
-
pass
|
2817
2848
|
pre_window_count = len(self.driver.window_handles)
|
2818
2849
|
outdated_driver = False
|
2819
2850
|
element = None
|
@@ -2874,7 +2905,7 @@ class BaseCase(unittest.TestCase):
|
|
2874
2905
|
timeout=None,
|
2875
2906
|
jquery=False,
|
2876
2907
|
):
|
2877
|
-
"""Drag
|
2908
|
+
"""Drag-and-drop an element from one selector to another."""
|
2878
2909
|
self.__check_scope()
|
2879
2910
|
if not timeout:
|
2880
2911
|
timeout = settings.SMALL_TIMEOUT
|
@@ -2886,6 +2917,9 @@ class BaseCase(unittest.TestCase):
|
|
2886
2917
|
drop_selector, drop_by = self.__recalculate_selector(
|
2887
2918
|
drop_selector, drop_by
|
2888
2919
|
)
|
2920
|
+
if self.__is_cdp_swap_needed():
|
2921
|
+
self.cdp.gui_drag_and_drop(drag_selector, drop_selector)
|
2922
|
+
return
|
2889
2923
|
drag_element = self.wait_for_element_clickable(
|
2890
2924
|
drag_selector, by=drag_by, timeout=timeout
|
2891
2925
|
)
|
@@ -2921,7 +2955,7 @@ class BaseCase(unittest.TestCase):
|
|
2921
2955
|
def drag_and_drop_with_offset(
|
2922
2956
|
self, selector, x, y, by="css selector", timeout=None
|
2923
2957
|
):
|
2924
|
-
"""Drag
|
2958
|
+
"""Drag-and-drop an element to an {X,Y}-offset location."""
|
2925
2959
|
self.__check_scope()
|
2926
2960
|
if not timeout:
|
2927
2961
|
timeout = settings.SMALL_TIMEOUT
|
@@ -3001,10 +3035,8 @@ class BaseCase(unittest.TestCase):
|
|
3001
3035
|
dropdown_selector, dropdown_by
|
3002
3036
|
)
|
3003
3037
|
pre_action_url = None
|
3004
|
-
|
3038
|
+
with suppress(Exception):
|
3005
3039
|
pre_action_url = self.driver.current_url
|
3006
|
-
except Exception:
|
3007
|
-
pass
|
3008
3040
|
pre_window_count = len(self.driver.window_handles)
|
3009
3041
|
try:
|
3010
3042
|
if option_by == "index":
|
@@ -3108,6 +3140,9 @@ class BaseCase(unittest.TestCase):
|
|
3108
3140
|
timeout = settings.SMALL_TIMEOUT
|
3109
3141
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
3110
3142
|
timeout = self.__get_new_timeout(timeout)
|
3143
|
+
if self.__is_cdp_swap_needed():
|
3144
|
+
self.cdp.select_option_by_text(dropdown_selector, option)
|
3145
|
+
return
|
3111
3146
|
self.__select_option(
|
3112
3147
|
dropdown_selector,
|
3113
3148
|
option,
|
@@ -3279,10 +3314,8 @@ class BaseCase(unittest.TestCase):
|
|
3279
3314
|
self.open("data:text/html,<head></head><body><div></div></body>")
|
3280
3315
|
inner_head = """document.getElementsByTagName("head")[0].innerHTML"""
|
3281
3316
|
inner_body = """document.getElementsByTagName("body")[0].innerHTML"""
|
3282
|
-
|
3317
|
+
with suppress(Exception):
|
3283
3318
|
self.wait_for_element_present("body", timeout=1)
|
3284
|
-
except Exception:
|
3285
|
-
pass
|
3286
3319
|
if not found_body:
|
3287
3320
|
self.execute_script('''%s = \"%s\"''' % (inner_body, html_string))
|
3288
3321
|
elif found_body and not found_head:
|
@@ -3356,6 +3389,8 @@ class BaseCase(unittest.TestCase):
|
|
3356
3389
|
|
3357
3390
|
def execute_script(self, script, *args, **kwargs):
|
3358
3391
|
self.__check_scope()
|
3392
|
+
if self.__is_cdp_swap_needed():
|
3393
|
+
return self.cdp.evaluate(script)
|
3359
3394
|
self._check_browser()
|
3360
3395
|
return self.driver.execute_script(script, *args, **kwargs)
|
3361
3396
|
|
@@ -3381,25 +3416,142 @@ class BaseCase(unittest.TestCase):
|
|
3381
3416
|
self.activate_jquery()
|
3382
3417
|
return self.driver.execute_script(script, *args, **kwargs)
|
3383
3418
|
|
3419
|
+
def get_element_at_x_y(self, x, y):
|
3420
|
+
"""Return element at current window's x,y coordinates."""
|
3421
|
+
self.__check_scope()
|
3422
|
+
self._check_browser()
|
3423
|
+
return self.execute_script(
|
3424
|
+
"return document.elementFromPoint(%s, %s);" % (x, y)
|
3425
|
+
)
|
3426
|
+
|
3427
|
+
def get_gui_element_rect(self, selector, by="css selector"):
|
3428
|
+
"""Very similar to element.rect, but the x, y coordinates are
|
3429
|
+
relative to the entire screen, rather than the browser window.
|
3430
|
+
This is specifically for PyAutoGUI actions on the full screen.
|
3431
|
+
(Note: There may be complications if iframes are involved.)"""
|
3432
|
+
if self.__is_cdp_swap_needed():
|
3433
|
+
return self.cdp.get_gui_element_rect(selector)
|
3434
|
+
element = self.wait_for_element_present(selector, by=by, timeout=1)
|
3435
|
+
element_rect = element.rect
|
3436
|
+
e_width = element_rect["width"]
|
3437
|
+
e_height = element_rect["height"]
|
3438
|
+
i_x = 0
|
3439
|
+
i_y = 0
|
3440
|
+
iframe_switch = False
|
3441
|
+
if self.__is_in_frame():
|
3442
|
+
self.switch_to_parent_frame()
|
3443
|
+
if self.__is_in_frame():
|
3444
|
+
raise Exception("Nested iframes breaks get_gui_element_rect!")
|
3445
|
+
iframe_switch = True
|
3446
|
+
iframe = self.wait_for_element_present("iframe", timeout=1)
|
3447
|
+
i_x = iframe.rect["x"]
|
3448
|
+
i_y = iframe.rect["y"]
|
3449
|
+
window_rect = self.get_window_rect()
|
3450
|
+
w_bottom_y = window_rect["y"] + window_rect["height"]
|
3451
|
+
viewport_height = self.execute_script("return window.innerHeight;")
|
3452
|
+
x = math.ceil(window_rect["x"] + i_x + element_rect["x"])
|
3453
|
+
y = math.ceil(w_bottom_y - viewport_height + i_y + element_rect["y"])
|
3454
|
+
y_scroll_offset = self.execute_script("return window.pageYOffset;")
|
3455
|
+
y = int(y - y_scroll_offset)
|
3456
|
+
if iframe_switch:
|
3457
|
+
self.switch_to_frame()
|
3458
|
+
if not self.is_element_present(selector, by=by):
|
3459
|
+
self.switch_to_parent_frame()
|
3460
|
+
return ({"height": e_height, "width": e_width, "x": x, "y": y})
|
3461
|
+
|
3462
|
+
def get_gui_element_center(self, selector, by="css selector"):
|
3463
|
+
"""Returns the x, y coordinates of the element's center based
|
3464
|
+
on the entire GUI / screen, rather than on the browser window.
|
3465
|
+
This is specifically for PyAutoGUI actions on the full screen.
|
3466
|
+
(Note: There may be complications if iframes are involved.)"""
|
3467
|
+
if self.__is_cdp_swap_needed():
|
3468
|
+
return self.cdp.get_gui_element_center(selector)
|
3469
|
+
element_rect = self.get_gui_element_rect(selector, by=by)
|
3470
|
+
x = element_rect["x"] + (element_rect["width"] / 2.0) + 0.5
|
3471
|
+
y = element_rect["y"] + (element_rect["height"] / 2.0) + 0.5
|
3472
|
+
return (x, y)
|
3473
|
+
|
3474
|
+
def get_screen_rect(self):
|
3475
|
+
self.__check_scope()
|
3476
|
+
if self.__is_cdp_swap_needed():
|
3477
|
+
return self.cdp.get_screen_rect()
|
3478
|
+
self._check_browser()
|
3479
|
+
return self.driver.get_screen_rect()
|
3480
|
+
|
3481
|
+
def get_window_rect(self):
|
3482
|
+
self.__check_scope()
|
3483
|
+
if self.__is_cdp_swap_needed():
|
3484
|
+
return self.cdp.get_window_rect()
|
3485
|
+
self._check_browser()
|
3486
|
+
return self.driver.get_window_rect()
|
3487
|
+
|
3488
|
+
def get_window_size(self):
|
3489
|
+
self.__check_scope()
|
3490
|
+
if self.__is_cdp_swap_needed():
|
3491
|
+
return self.cdp.get_window_size()
|
3492
|
+
self._check_browser()
|
3493
|
+
return self.driver.get_window_size()
|
3494
|
+
|
3495
|
+
def get_window_position(self):
|
3496
|
+
self.__check_scope()
|
3497
|
+
if self.__is_cdp_swap_needed():
|
3498
|
+
return self.cdp.get_window_position()
|
3499
|
+
self._check_browser()
|
3500
|
+
return self.driver.get_window_position()
|
3501
|
+
|
3384
3502
|
def set_window_rect(self, x, y, width, height):
|
3385
3503
|
self.__check_scope()
|
3504
|
+
if self.__is_cdp_swap_needed():
|
3505
|
+
self.cdp.set_window_rect(x, y, width, height)
|
3506
|
+
return
|
3386
3507
|
self._check_browser()
|
3387
3508
|
self.driver.set_window_rect(x, y, width, height)
|
3388
|
-
self.__demo_mode_pause_if_active()
|
3509
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3389
3510
|
|
3390
3511
|
def set_window_size(self, width, height):
|
3391
3512
|
self.__check_scope()
|
3392
3513
|
self._check_browser()
|
3393
3514
|
self.driver.set_window_size(width, height)
|
3394
|
-
self.__demo_mode_pause_if_active()
|
3515
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3516
|
+
|
3517
|
+
def set_window_position(self, x, y):
|
3518
|
+
self.__check_scope()
|
3519
|
+
self._check_browser()
|
3520
|
+
self.driver.set_window_position(x, y)
|
3521
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3395
3522
|
|
3396
3523
|
def maximize_window(self):
|
3397
3524
|
self.__check_scope()
|
3525
|
+
if self.__is_cdp_swap_needed():
|
3526
|
+
self.cdp.maximize()
|
3527
|
+
return
|
3398
3528
|
self._check_browser()
|
3399
3529
|
self.driver.maximize_window()
|
3400
|
-
self.__demo_mode_pause_if_active()
|
3530
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3531
|
+
|
3532
|
+
def minimize_window(self):
|
3533
|
+
self.__check_scope()
|
3534
|
+
if self.__is_cdp_swap_needed():
|
3535
|
+
self.cdp.minimize()
|
3536
|
+
return
|
3537
|
+
self._check_browser()
|
3538
|
+
self.driver.minimize_window()
|
3539
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3540
|
+
|
3541
|
+
def reset_window_size(self):
|
3542
|
+
self.__check_scope()
|
3543
|
+
if self.__is_cdp_swap_needed():
|
3544
|
+
self.cdp.reset_window_size()
|
3545
|
+
return
|
3546
|
+
self._check_browser()
|
3547
|
+
x = settings.WINDOW_START_X
|
3548
|
+
y = settings.WINDOW_START_Y
|
3549
|
+
width = settings.CHROME_START_WIDTH
|
3550
|
+
height = settings.CHROME_START_HEIGHT
|
3551
|
+
self.set_window_rect(x, y, width, height)
|
3552
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3401
3553
|
|
3402
|
-
def switch_to_frame(self, frame, timeout=None):
|
3554
|
+
def switch_to_frame(self, frame="iframe", timeout=None):
|
3403
3555
|
"""Wait for an iframe to appear, and switch to it. This should be
|
3404
3556
|
usable as a drop-in replacement for driver.switch_to.frame().
|
3405
3557
|
The iframe identifier can be a selector, an index, an id, a name,
|
@@ -3726,7 +3878,11 @@ class BaseCase(unittest.TestCase):
|
|
3726
3878
|
"""Opens a new browser tab/window and switches to it by default."""
|
3727
3879
|
self.wait_for_ready_state_complete()
|
3728
3880
|
if switch_to:
|
3729
|
-
|
3881
|
+
try:
|
3882
|
+
self.driver.switch_to.new_window("tab")
|
3883
|
+
except Exception:
|
3884
|
+
self.driver.execute_script("window.open('');")
|
3885
|
+
self.switch_to_newest_window()
|
3730
3886
|
else:
|
3731
3887
|
self.driver.execute_script("window.open('');")
|
3732
3888
|
time.sleep(0.01)
|
@@ -3767,6 +3923,7 @@ class BaseCase(unittest.TestCase):
|
|
3767
3923
|
cap_file=None,
|
3768
3924
|
cap_string=None,
|
3769
3925
|
recorder_ext=None,
|
3926
|
+
disable_cookies=None,
|
3770
3927
|
disable_js=None,
|
3771
3928
|
disable_csp=None,
|
3772
3929
|
enable_ws=None,
|
@@ -3778,6 +3935,7 @@ class BaseCase(unittest.TestCase):
|
|
3778
3935
|
log_cdp_events=None,
|
3779
3936
|
no_sandbox=None,
|
3780
3937
|
disable_gpu=None,
|
3938
|
+
headless1=None,
|
3781
3939
|
headless2=None,
|
3782
3940
|
incognito=None,
|
3783
3941
|
guest_mode=None,
|
@@ -3826,6 +3984,7 @@ class BaseCase(unittest.TestCase):
|
|
3826
3984
|
cap_file - the file containing desired capabilities for the browser
|
3827
3985
|
cap_string - the string with desired capabilities for the browser
|
3828
3986
|
recorder_ext - the option to enable the SBase Recorder extension
|
3987
|
+
disable_cookies - the option to disable Cookies (May break things!)
|
3829
3988
|
disable_js - the option to disable JavaScript (May break websites!)
|
3830
3989
|
disable_csp - an option to disable Chrome's Content Security Policy
|
3831
3990
|
enable_ws - the option to enable the Web Security feature (Chrome)
|
@@ -3837,6 +3996,7 @@ class BaseCase(unittest.TestCase):
|
|
3837
3996
|
log_cdp_events - capture {"performance": "ALL", "browser": "ALL"})
|
3838
3997
|
no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
|
3839
3998
|
disable_gpu - the option to enable Chrome's "Disable GPU" feature
|
3999
|
+
headless1 - the option to use the older headless mode (Chromium)
|
3840
4000
|
headless2 - the option to use the newer headless mode (Chromium)
|
3841
4001
|
incognito - the option to enable Chrome's Incognito mode (Chrome)
|
3842
4002
|
guest_mode - the option to enable Chrome's Guest mode (Chrome)
|
@@ -3923,6 +4083,8 @@ class BaseCase(unittest.TestCase):
|
|
3923
4083
|
user_agent = self.user_agent
|
3924
4084
|
if recorder_ext is None:
|
3925
4085
|
recorder_ext = self.recorder_ext
|
4086
|
+
if disable_cookies is None:
|
4087
|
+
disable_cookies = self.disable_cookies
|
3926
4088
|
if disable_js is None:
|
3927
4089
|
disable_js = self.disable_js
|
3928
4090
|
if disable_csp is None:
|
@@ -3945,6 +4107,8 @@ class BaseCase(unittest.TestCase):
|
|
3945
4107
|
no_sandbox = self.no_sandbox
|
3946
4108
|
if disable_gpu is None:
|
3947
4109
|
disable_gpu = self.disable_gpu
|
4110
|
+
if headless1 is None:
|
4111
|
+
headless1 = self.headless1
|
3948
4112
|
if headless2 is None:
|
3949
4113
|
headless2 = self.headless2
|
3950
4114
|
if incognito is None:
|
@@ -4016,8 +4180,6 @@ class BaseCase(unittest.TestCase):
|
|
4016
4180
|
"Valid options = {%s}" % (browser, valid_browsers)
|
4017
4181
|
)
|
4018
4182
|
# Launch a web browser
|
4019
|
-
from seleniumbase.core import browser_launcher
|
4020
|
-
|
4021
4183
|
new_driver = browser_launcher.get_driver(
|
4022
4184
|
browser_name=browser_name,
|
4023
4185
|
headless=headless,
|
@@ -4034,6 +4196,7 @@ class BaseCase(unittest.TestCase):
|
|
4034
4196
|
cap_file=cap_file,
|
4035
4197
|
cap_string=cap_string,
|
4036
4198
|
recorder_ext=recorder_ext,
|
4199
|
+
disable_cookies=disable_cookies,
|
4037
4200
|
disable_js=disable_js,
|
4038
4201
|
disable_csp=disable_csp,
|
4039
4202
|
enable_ws=enable_ws,
|
@@ -4045,6 +4208,7 @@ class BaseCase(unittest.TestCase):
|
|
4045
4208
|
log_cdp_events=log_cdp_events,
|
4046
4209
|
no_sandbox=no_sandbox,
|
4047
4210
|
disable_gpu=disable_gpu,
|
4211
|
+
headless1=headless1,
|
4048
4212
|
headless2=headless2,
|
4049
4213
|
incognito=incognito,
|
4050
4214
|
guest_mode=guest_mode,
|
@@ -4113,7 +4277,8 @@ class BaseCase(unittest.TestCase):
|
|
4113
4277
|
self.driver.maximize_window()
|
4114
4278
|
self.wait_for_ready_state_complete()
|
4115
4279
|
else:
|
4116
|
-
|
4280
|
+
with suppress(Exception):
|
4281
|
+
self.driver.set_window_size(width, height)
|
4117
4282
|
except Exception:
|
4118
4283
|
pass # Keep existing browser resolution
|
4119
4284
|
elif self.browser == "safari":
|
@@ -4124,10 +4289,8 @@ class BaseCase(unittest.TestCase):
|
|
4124
4289
|
except Exception:
|
4125
4290
|
pass # Keep existing browser resolution
|
4126
4291
|
else:
|
4127
|
-
|
4128
|
-
self.driver.set_window_rect(10,
|
4129
|
-
except Exception:
|
4130
|
-
pass
|
4292
|
+
with suppress(Exception):
|
4293
|
+
self.driver.set_window_rect(10, 46, width, height)
|
4131
4294
|
if self.start_page and len(self.start_page) >= 4:
|
4132
4295
|
if page_utils.is_valid_url(self.start_page):
|
4133
4296
|
self.open(self.start_page)
|
@@ -4137,6 +4300,51 @@ class BaseCase(unittest.TestCase):
|
|
4137
4300
|
self.__dont_record_open = True
|
4138
4301
|
self.open(new_start_page)
|
4139
4302
|
self.__dont_record_open = False
|
4303
|
+
if undetectable:
|
4304
|
+
if hasattr(new_driver, "cdp"):
|
4305
|
+
self.cdp = new_driver.cdp
|
4306
|
+
if hasattr(new_driver, "uc_open"):
|
4307
|
+
self.uc_open = new_driver.uc_open
|
4308
|
+
if hasattr(new_driver, "uc_open_with_tab"):
|
4309
|
+
self.uc_open_with_tab = new_driver.uc_open_with_tab
|
4310
|
+
if hasattr(new_driver, "uc_open_with_reconnect"):
|
4311
|
+
self.uc_open_with_reconnect = new_driver.uc_open_with_reconnect
|
4312
|
+
if hasattr(new_driver, "uc_open_with_cdp_mode"):
|
4313
|
+
self.uc_open_with_cdp_mode = new_driver.uc_open_with_cdp_mode
|
4314
|
+
if hasattr(new_driver, "uc_open_with_disconnect"):
|
4315
|
+
self.uc_open_with_disconnect = (
|
4316
|
+
new_driver.uc_open_with_disconnect
|
4317
|
+
)
|
4318
|
+
if hasattr(new_driver, "reconnect"):
|
4319
|
+
self.reconnect = new_driver.reconnect
|
4320
|
+
if hasattr(new_driver, "disconnect"):
|
4321
|
+
self.disconnect = new_driver.disconnect
|
4322
|
+
if hasattr(new_driver, "connect"):
|
4323
|
+
self.connect = new_driver.connect
|
4324
|
+
if hasattr(new_driver, "uc_click"):
|
4325
|
+
self.uc_click = new_driver.uc_click
|
4326
|
+
if hasattr(new_driver, "uc_gui_press_key"):
|
4327
|
+
self.uc_gui_press_key = new_driver.uc_gui_press_key
|
4328
|
+
if hasattr(new_driver, "uc_gui_press_keys"):
|
4329
|
+
self.uc_gui_press_keys = new_driver.uc_gui_press_keys
|
4330
|
+
if hasattr(new_driver, "uc_gui_write"):
|
4331
|
+
self.uc_gui_write = new_driver.uc_gui_write
|
4332
|
+
if hasattr(new_driver, "uc_gui_click_x_y"):
|
4333
|
+
self.uc_gui_click_x_y = new_driver.uc_gui_click_x_y
|
4334
|
+
if hasattr(new_driver, "uc_gui_click_captcha"):
|
4335
|
+
self.uc_gui_click_captcha = new_driver.uc_gui_click_captcha
|
4336
|
+
if hasattr(new_driver, "uc_gui_click_cf"):
|
4337
|
+
self.uc_gui_click_cf = new_driver.uc_gui_click_cf
|
4338
|
+
if hasattr(new_driver, "uc_gui_click_rc"):
|
4339
|
+
self.uc_gui_click_rc = new_driver.uc_gui_click_rc
|
4340
|
+
if hasattr(new_driver, "uc_gui_handle_captcha"):
|
4341
|
+
self.uc_gui_handle_captcha = new_driver.uc_gui_handle_captcha
|
4342
|
+
if hasattr(new_driver, "uc_gui_handle_cf"):
|
4343
|
+
self.uc_gui_handle_cf = new_driver.uc_gui_handle_cf
|
4344
|
+
if hasattr(new_driver, "uc_gui_handle_rc"):
|
4345
|
+
self.uc_gui_handle_rc = new_driver.uc_gui_handle_rc
|
4346
|
+
if hasattr(new_driver, "uc_switch_to_frame"):
|
4347
|
+
self.uc_switch_to_frame = new_driver.uc_switch_to_frame
|
4140
4348
|
return new_driver
|
4141
4349
|
|
4142
4350
|
def switch_to_driver(self, driver):
|
@@ -4166,6 +4374,9 @@ class BaseCase(unittest.TestCase):
|
|
4166
4374
|
If a provided selector is not found, then takes a full-page screenshot.
|
4167
4375
|
If the folder provided doesn't exist, it will get created.
|
4168
4376
|
The screenshot will be in PNG format: (*.png)"""
|
4377
|
+
if self.__is_cdp_swap_needed():
|
4378
|
+
self.cdp.save_screenshot(name, folder=folder, selector=selector)
|
4379
|
+
return
|
4169
4380
|
self.wait_for_ready_state_complete()
|
4170
4381
|
if selector and by:
|
4171
4382
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -4281,7 +4492,8 @@ class BaseCase(unittest.TestCase):
|
|
4281
4492
|
@Params
|
4282
4493
|
name - The file name to save the current page's HTML to.
|
4283
4494
|
folder - The folder to save the file to. (Default = current folder)"""
|
4284
|
-
self.
|
4495
|
+
if not self.__is_cdp_swap_needed():
|
4496
|
+
self.wait_for_ready_state_complete()
|
4285
4497
|
return page_actions.save_page_source(self.driver, name, folder)
|
4286
4498
|
|
4287
4499
|
def save_cookies(self, name="cookies.txt"):
|
@@ -4309,35 +4521,39 @@ class BaseCase(unittest.TestCase):
|
|
4309
4521
|
cookies_file.writelines(json_cookies)
|
4310
4522
|
cookies_file.close()
|
4311
4523
|
|
4312
|
-
def load_cookies(self, name="cookies.txt"):
|
4313
|
-
"""
|
4524
|
+
def load_cookies(self, name="cookies.txt", expiry=False):
|
4525
|
+
"""
|
4526
|
+
Loads the page cookies from the "saved_cookies" folder.
|
4527
|
+
Usage for setting expiry:
|
4528
|
+
If expiry == 0 or False: Delete "expiry".
|
4529
|
+
If expiry == -1 (or < 0): Do not modify "expiry".
|
4530
|
+
If expiry > 0: Set "expiry" to expiry minutes in the future.
|
4531
|
+
If expiry == True: Set "expiry" to 24 hours in the future.
|
4532
|
+
"""
|
4533
|
+
cookies = self.get_saved_cookies(name)
|
4314
4534
|
self.wait_for_ready_state_complete()
|
4315
|
-
|
4316
|
-
|
4317
|
-
if "/" in name:
|
4318
|
-
name = name.split("/")[-1]
|
4319
|
-
if "\\" in name:
|
4320
|
-
name = name.split("\\")[-1]
|
4321
|
-
if len(name) < 1:
|
4322
|
-
raise Exception("Filename for Cookies is too short!")
|
4323
|
-
if not name.endswith(".txt"):
|
4324
|
-
name = name + ".txt"
|
4325
|
-
folder = constants.SavedCookies.STORAGE_FOLDER
|
4326
|
-
abs_path = os.path.abspath(".")
|
4327
|
-
file_path = os.path.join(abs_path, folder)
|
4328
|
-
cookies_file_path = os.path.join(file_path, name)
|
4329
|
-
json_cookies = None
|
4330
|
-
with open(cookies_file_path, "r") as f:
|
4331
|
-
json_cookies = f.read().strip()
|
4332
|
-
cookies = json.loads(json_cookies)
|
4535
|
+
origin = self.get_origin()
|
4536
|
+
trim_origin = origin.split("://")[-1]
|
4333
4537
|
for cookie in cookies:
|
4334
|
-
if "
|
4538
|
+
if "domain" in cookie:
|
4539
|
+
if cookie["domain"] not in origin:
|
4540
|
+
cookie["domain"] = trim_origin
|
4541
|
+
if "expiry" in cookie and (not expiry or expiry == 0):
|
4335
4542
|
del cookie["expiry"]
|
4543
|
+
elif isinstance(expiry, (int, float)) and expiry < 0:
|
4544
|
+
pass
|
4545
|
+
elif isinstance(expiry, (int, float)) and expiry > 0:
|
4546
|
+
cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
|
4547
|
+
elif expiry:
|
4548
|
+
cookie["expiry"] = int(time.time()) + 86400
|
4336
4549
|
self.driver.add_cookie(cookie)
|
4337
4550
|
|
4338
4551
|
def delete_all_cookies(self):
|
4339
4552
|
"""Deletes all cookies in the web browser.
|
4340
4553
|
Does NOT delete the saved cookies file."""
|
4554
|
+
if self.__is_cdp_swap_needed():
|
4555
|
+
self.cdp.clear_cookies()
|
4556
|
+
return
|
4341
4557
|
self.wait_for_ready_state_complete()
|
4342
4558
|
self.driver.delete_all_cookies()
|
4343
4559
|
if self.recorder_mode:
|
@@ -4349,7 +4565,6 @@ class BaseCase(unittest.TestCase):
|
|
4349
4565
|
def delete_saved_cookies(self, name="cookies.txt"):
|
4350
4566
|
"""Deletes the cookies file from the "saved_cookies" folder.
|
4351
4567
|
Does NOT delete the cookies from the web browser."""
|
4352
|
-
self.wait_for_ready_state_complete()
|
4353
4568
|
if name.endswith("/"):
|
4354
4569
|
raise Exception("Invalid filename for Cookies!")
|
4355
4570
|
if "/" in name:
|
@@ -4366,11 +4581,129 @@ class BaseCase(unittest.TestCase):
|
|
4366
4581
|
if cookies_file_path.endswith(".txt"):
|
4367
4582
|
os.remove(cookies_file_path)
|
4368
4583
|
|
4584
|
+
def get_saved_cookies(self, name="cookies.txt"):
|
4585
|
+
"""Gets the page cookies from the "saved_cookies" folder."""
|
4586
|
+
if name.endswith("/"):
|
4587
|
+
raise Exception("Invalid filename for Cookies!")
|
4588
|
+
if "/" in name:
|
4589
|
+
name = name.split("/")[-1]
|
4590
|
+
if "\\" in name:
|
4591
|
+
name = name.split("\\")[-1]
|
4592
|
+
if len(name) < 1:
|
4593
|
+
raise Exception("Filename for Cookies is too short!")
|
4594
|
+
if not name.endswith(".txt"):
|
4595
|
+
name = name + ".txt"
|
4596
|
+
folder = constants.SavedCookies.STORAGE_FOLDER
|
4597
|
+
abs_path = os.path.abspath(".")
|
4598
|
+
file_path = os.path.join(abs_path, folder)
|
4599
|
+
cookies_file_path = os.path.join(file_path, name)
|
4600
|
+
json_cookies = None
|
4601
|
+
with open(cookies_file_path, "r") as f:
|
4602
|
+
json_cookies = f.read().strip()
|
4603
|
+
return json.loads(json_cookies)
|
4604
|
+
|
4605
|
+
def get_cookie(self, name):
|
4606
|
+
self.__check_scope()
|
4607
|
+
self._check_browser()
|
4608
|
+
return self.driver.get_cookie(name)
|
4609
|
+
|
4610
|
+
def get_cookies(self):
|
4611
|
+
self.__check_scope()
|
4612
|
+
self._check_browser()
|
4613
|
+
return self.driver.get_cookies()
|
4614
|
+
|
4615
|
+
def get_cookie_string(self):
|
4616
|
+
self.__check_scope()
|
4617
|
+
if self.__is_cdp_swap_needed():
|
4618
|
+
return self.cdp.get_cookie_string()
|
4619
|
+
self._check_browser()
|
4620
|
+
return self.execute_script("return document.cookie;")
|
4621
|
+
|
4622
|
+
def add_cookie(self, cookie_dict, expiry=False):
|
4623
|
+
"""Usage examples:
|
4624
|
+
self.add_cookie({'name': 'foo', 'value': 'bar'})
|
4625
|
+
self.add_cookie({'name': 'foo', 'value': 'bar', 'path': '/'})
|
4626
|
+
self.add_cookie({'name': 'foo', 'value': 'bar', 'secure': True})
|
4627
|
+
self.add_cookie({'name': 'foo', 'value': 'bar', 'sameSite': 'Strict'})
|
4628
|
+
Usage for setting expiry:
|
4629
|
+
If expiry == 0 or False: Delete "expiry".
|
4630
|
+
If expiry == -1 (or < 0): Do not modify "expiry".
|
4631
|
+
If expiry > 0: Set "expiry" to expiry minutes in the future.
|
4632
|
+
If expiry == True: Set "expiry" to 24 hours in the future.
|
4633
|
+
"""
|
4634
|
+
self.__check_scope()
|
4635
|
+
self._check_browser()
|
4636
|
+
cookie = cookie_dict
|
4637
|
+
if "domain" in cookie:
|
4638
|
+
origin = self.get_origin()
|
4639
|
+
trim_origin = origin.split("://")[-1]
|
4640
|
+
if cookie["domain"] not in origin:
|
4641
|
+
cookie["domain"] = trim_origin
|
4642
|
+
if "expiry" in cookie and (not expiry or expiry == 0):
|
4643
|
+
del cookie["expiry"]
|
4644
|
+
elif isinstance(expiry, (int, float)) and expiry < 0:
|
4645
|
+
pass
|
4646
|
+
elif isinstance(expiry, (int, float)) and expiry > 0:
|
4647
|
+
cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
|
4648
|
+
elif expiry:
|
4649
|
+
cookie["expiry"] = int(time.time()) + 86400
|
4650
|
+
self.driver.add_cookie(cookie_dict)
|
4651
|
+
|
4652
|
+
def add_cookies(self, cookies, expiry=False):
|
4653
|
+
"""
|
4654
|
+
Usage for setting expiry:
|
4655
|
+
If expiry == 0 or False: Delete "expiry".
|
4656
|
+
If expiry == -1 (or < 0): Do not modify "expiry".
|
4657
|
+
If expiry > 0: Set "expiry" to expiry minutes in the future.
|
4658
|
+
If expiry == True: Set "expiry" to 24 hours in the future.
|
4659
|
+
"""
|
4660
|
+
self.__check_scope()
|
4661
|
+
self._check_browser()
|
4662
|
+
origin = self.get_origin()
|
4663
|
+
trim_origin = origin.split("://")[-1]
|
4664
|
+
for cookie in cookies:
|
4665
|
+
if "domain" in cookie:
|
4666
|
+
if cookie["domain"] not in origin:
|
4667
|
+
cookie["domain"] = trim_origin
|
4668
|
+
if "expiry" in cookie and (not expiry or expiry == 0):
|
4669
|
+
del cookie["expiry"]
|
4670
|
+
elif isinstance(expiry, (int, float)) and expiry < 0:
|
4671
|
+
pass
|
4672
|
+
elif isinstance(expiry, (int, float)) and expiry > 0:
|
4673
|
+
cookie["expiry"] = int(time.time()) + int(expiry * 60.0)
|
4674
|
+
elif expiry:
|
4675
|
+
cookie["expiry"] = int(time.time()) + 86400
|
4676
|
+
self.driver.add_cookie(cookie)
|
4677
|
+
|
4678
|
+
def __set_esc_skip(self):
|
4679
|
+
if hasattr(self, "esc_end") and self.esc_end:
|
4680
|
+
script = (
|
4681
|
+
"""document.onkeydown = function(evt) {
|
4682
|
+
evt = evt || window.event;
|
4683
|
+
var isEscape = false;
|
4684
|
+
if ("key" in evt) {
|
4685
|
+
isEscape = (evt.key === "Escape" || evt.key === "Esc");
|
4686
|
+
} else {
|
4687
|
+
isEscape = (evt.keyCode === 27);
|
4688
|
+
}
|
4689
|
+
if (isEscape) {
|
4690
|
+
document.sb_esc_end = 'yes';
|
4691
|
+
}
|
4692
|
+
};"""
|
4693
|
+
)
|
4694
|
+
self.execute_script(script)
|
4695
|
+
|
4696
|
+
def __skip_if_esc(self):
|
4697
|
+
if hasattr(self, "esc_end") and self.esc_end:
|
4698
|
+
if self.execute_script("return document.sb_esc_end;") == "yes":
|
4699
|
+
self.skip()
|
4700
|
+
|
4369
4701
|
def wait_for_ready_state_complete(self, timeout=None):
|
4370
4702
|
"""Waits for the "readyState" of the page to be "complete".
|
4371
4703
|
Returns True when the method completes."""
|
4372
4704
|
self.__check_scope()
|
4373
4705
|
self._check_browser()
|
4706
|
+
self.__skip_if_esc()
|
4374
4707
|
if not timeout:
|
4375
4708
|
timeout = settings.EXTREME_TIMEOUT
|
4376
4709
|
if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
|
@@ -4389,6 +4722,7 @@ class BaseCase(unittest.TestCase):
|
|
4389
4722
|
time.sleep(0.01)
|
4390
4723
|
if self.undetectable:
|
4391
4724
|
time.sleep(0.035)
|
4725
|
+
self.__set_esc_skip()
|
4392
4726
|
return True
|
4393
4727
|
|
4394
4728
|
def wait_for_angularjs(self, timeout=None, **kwargs):
|
@@ -4476,24 +4810,35 @@ class BaseCase(unittest.TestCase):
|
|
4476
4810
|
script = """document.designMode = 'on';"""
|
4477
4811
|
self.execute_script(script)
|
4478
4812
|
|
4479
|
-
def deactivate_design_mode(self):
|
4813
|
+
def deactivate_design_mode(self, url=None):
|
4480
4814
|
# Deactivate Chrome's Design Mode.
|
4481
4815
|
self.wait_for_ready_state_complete()
|
4482
4816
|
script = """document.designMode = 'off';"""
|
4483
4817
|
self.execute_script(script)
|
4484
4818
|
|
4819
|
+
def activate_cdp_mode(self, url=None):
|
4820
|
+
if hasattr(self.driver, "_is_using_uc") and self.driver._is_using_uc:
|
4821
|
+
self.driver.uc_open_with_cdp_mode(url)
|
4822
|
+
else:
|
4823
|
+
self.get_new_driver(undetectable=True)
|
4824
|
+
self.driver.uc_open_with_cdp_mode(url)
|
4825
|
+
self.cdp = self.driver.cdp
|
4826
|
+
|
4485
4827
|
def activate_recorder(self):
|
4486
4828
|
from seleniumbase.js_code.recorder_js import recorder_js
|
4487
4829
|
|
4488
4830
|
if not self.is_chromium():
|
4831
|
+
if "linux" not in sys.platform:
|
4832
|
+
c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
|
4833
|
+
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX
|
4834
|
+
cr = colorama.Style.RESET_ALL
|
4835
|
+
sc = c1 + "Selenium" + c2 + "Base" + cr
|
4489
4836
|
raise Exception(
|
4490
|
-
"The Recorder is
|
4837
|
+
"The %s Recorder is for Chromium only!\n"
|
4838
|
+
" (Supported browsers: Chrome and Edge)" % sc
|
4491
4839
|
)
|
4492
4840
|
url = self.driver.current_url
|
4493
|
-
if (
|
4494
|
-
url.startswith("data:") or url.startswith("about:")
|
4495
|
-
or url.startswith("chrome:") or url.startswith("edge:")
|
4496
|
-
):
|
4841
|
+
if url.startswith(("data:", "about:", "chrome:", "edge:")):
|
4497
4842
|
message = (
|
4498
4843
|
"The URL in Recorder-Mode cannot start with: "
|
4499
4844
|
'"data:", "about:", "chrome:", or "edge:"!'
|
@@ -4502,7 +4847,7 @@ class BaseCase(unittest.TestCase):
|
|
4502
4847
|
return
|
4503
4848
|
if self.recorder_ext:
|
4504
4849
|
return # The Recorder extension is already active
|
4505
|
-
|
4850
|
+
with suppress(Exception):
|
4506
4851
|
recorder_on = self.get_session_storage_item("recorder_activated")
|
4507
4852
|
if not recorder_on == "yes":
|
4508
4853
|
self.execute_script(recorder_js)
|
@@ -4511,8 +4856,6 @@ class BaseCase(unittest.TestCase):
|
|
4511
4856
|
print("\n" + message)
|
4512
4857
|
p_msg = "Recorder Mode ACTIVE.<br>[ESC]: Pause. [~`]: Resume."
|
4513
4858
|
self.post_message(p_msg, pause=False, style="error")
|
4514
|
-
except Exception:
|
4515
|
-
pass
|
4516
4859
|
|
4517
4860
|
def __current_url_is_recordable(self):
|
4518
4861
|
url = self.get_current_url()
|
@@ -4552,10 +4895,7 @@ class BaseCase(unittest.TestCase):
|
|
4552
4895
|
|
4553
4896
|
def __get_recorded_actions_on_active_tab(self):
|
4554
4897
|
url = self.driver.current_url
|
4555
|
-
if (
|
4556
|
-
url.startswith("data:") or url.startswith("about:")
|
4557
|
-
or url.startswith("chrome:") or url.startswith("edge:")
|
4558
|
-
):
|
4898
|
+
if url.startswith(("data:", "about:", "chrome:", "edge:")):
|
4559
4899
|
return []
|
4560
4900
|
self.__origins_to_save.append(self.get_origin())
|
4561
4901
|
actions = self.get_session_storage_item("recorded_actions")
|
@@ -4566,9 +4906,9 @@ class BaseCase(unittest.TestCase):
|
|
4566
4906
|
return []
|
4567
4907
|
|
4568
4908
|
def __process_recorded_actions(self):
|
4909
|
+
"""Generates code after the SeleniumBase Recorder runs."""
|
4569
4910
|
if self.driver is None:
|
4570
4911
|
return
|
4571
|
-
import colorama
|
4572
4912
|
from seleniumbase.core import recorder_helper
|
4573
4913
|
|
4574
4914
|
raw_actions = [] # All raw actions from sessionStorage
|
@@ -4770,10 +5110,7 @@ class BaseCase(unittest.TestCase):
|
|
4770
5110
|
or srt_actions[n - 1][0] == "jq_cl"
|
4771
5111
|
or srt_actions[n - 1][0] == "jq_ca"
|
4772
5112
|
):
|
4773
|
-
if (
|
4774
|
-
srt_actions[n - 1][1].startswith("input")
|
4775
|
-
or srt_actions[n - 1][1].startswith("button")
|
4776
|
-
):
|
5113
|
+
if srt_actions[n - 1][1].startswith(("input", "button")):
|
4777
5114
|
srt_actions[n][0] = "f_url"
|
4778
5115
|
elif srt_actions[n - 1][0] == "input":
|
4779
5116
|
if srt_actions[n - 1][2].endswith("\n"):
|
@@ -5121,7 +5458,6 @@ class BaseCase(unittest.TestCase):
|
|
5121
5458
|
and (filename == "base_case.py" or methodname == "runTest")
|
5122
5459
|
):
|
5123
5460
|
import traceback
|
5124
|
-
|
5125
5461
|
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
5126
5462
|
test_base = stack_base.split(", in ")[0]
|
5127
5463
|
if hasattr(self, "cm_filename") and self.cm_filename:
|
@@ -5169,7 +5505,10 @@ class BaseCase(unittest.TestCase):
|
|
5169
5505
|
new_file = True
|
5170
5506
|
sb_config._recorded_actions[filename] = []
|
5171
5507
|
data.append("from seleniumbase import BaseCase")
|
5172
|
-
|
5508
|
+
if "--uc" in sys.argv:
|
5509
|
+
data.append('BaseCase.main(__name__, __file__, "--uc")')
|
5510
|
+
else:
|
5511
|
+
data.append("BaseCase.main(__name__, __file__)")
|
5173
5512
|
data.append("")
|
5174
5513
|
data.append("")
|
5175
5514
|
data.append("class %s(BaseCase):" % classname)
|
@@ -5179,7 +5518,13 @@ class BaseCase(unittest.TestCase):
|
|
5179
5518
|
data.append("class %s(BaseCase):" % classname)
|
5180
5519
|
data.append(" def %s(self):" % methodname)
|
5181
5520
|
if len(sb_actions) > 0:
|
5521
|
+
if "--uc" in sys.argv:
|
5522
|
+
data.append(" self.activate_cdp_mode()")
|
5182
5523
|
for action in sb_actions:
|
5524
|
+
if "--uc" in sys.argv:
|
5525
|
+
action = action.replace(
|
5526
|
+
"self.type(", "self.press_keys("
|
5527
|
+
)
|
5183
5528
|
data.append(" " + action)
|
5184
5529
|
else:
|
5185
5530
|
data.append(" pass")
|
@@ -5191,11 +5536,9 @@ class BaseCase(unittest.TestCase):
|
|
5191
5536
|
if recordings_folder.endswith("/"):
|
5192
5537
|
recordings_folder = recordings_folder[:-1]
|
5193
5538
|
if not os.path.exists(recordings_folder):
|
5194
|
-
|
5539
|
+
with suppress(Exception):
|
5195
5540
|
os.makedirs(recordings_folder)
|
5196
5541
|
sys.stdout.write("\nCreated recordings%s" % os.sep)
|
5197
|
-
except Exception:
|
5198
|
-
pass
|
5199
5542
|
|
5200
5543
|
data = []
|
5201
5544
|
data.append("")
|
@@ -5296,12 +5639,10 @@ class BaseCase(unittest.TestCase):
|
|
5296
5639
|
if not new_file:
|
5297
5640
|
rec_message = ">>> RECORDING ADDED to: "
|
5298
5641
|
star_len = len(rec_message) + len(file_path)
|
5299
|
-
|
5642
|
+
with suppress(Exception):
|
5300
5643
|
terminal_size = os.get_terminal_size().columns
|
5301
5644
|
if terminal_size > 30 and star_len > terminal_size:
|
5302
5645
|
star_len = terminal_size
|
5303
|
-
except Exception:
|
5304
|
-
pass
|
5305
5646
|
spc = "\n\n"
|
5306
5647
|
if hasattr(self, "rec_print") and self.rec_print:
|
5307
5648
|
spc = ""
|
@@ -5361,6 +5702,9 @@ class BaseCase(unittest.TestCase):
|
|
5361
5702
|
data.append(" Scenario: %s" % scenario_test)
|
5362
5703
|
if len(behave_actions) > 0:
|
5363
5704
|
count = 0
|
5705
|
+
if "--uc" in sys.argv:
|
5706
|
+
data.append(" Given Activate CDP Mode")
|
5707
|
+
count += 1
|
5364
5708
|
for action in behave_actions:
|
5365
5709
|
if count == 0:
|
5366
5710
|
data.append(" Given " + action)
|
@@ -5374,22 +5718,16 @@ class BaseCase(unittest.TestCase):
|
|
5374
5718
|
if recordings_folder.endswith("/"):
|
5375
5719
|
recordings_folder = recordings_folder[:-1]
|
5376
5720
|
if not os.path.exists(recordings_folder):
|
5377
|
-
|
5721
|
+
with suppress(Exception):
|
5378
5722
|
os.makedirs(recordings_folder)
|
5379
|
-
except Exception:
|
5380
|
-
pass
|
5381
5723
|
features_folder = os.path.join(recordings_folder, "features")
|
5382
5724
|
if not os.path.exists(features_folder):
|
5383
|
-
|
5725
|
+
with suppress(Exception):
|
5384
5726
|
os.makedirs(features_folder)
|
5385
|
-
except Exception:
|
5386
|
-
pass
|
5387
5727
|
steps_folder = os.path.join(features_folder, "steps")
|
5388
5728
|
if not os.path.exists(steps_folder):
|
5389
|
-
|
5729
|
+
with suppress(Exception):
|
5390
5730
|
os.makedirs(steps_folder)
|
5391
|
-
except Exception:
|
5392
|
-
pass
|
5393
5731
|
|
5394
5732
|
file_name = filename.split(".")[0]
|
5395
5733
|
if hasattr(self, "is_behave") and self.is_behave:
|
@@ -5404,12 +5742,10 @@ class BaseCase(unittest.TestCase):
|
|
5404
5742
|
if not new_file:
|
5405
5743
|
rec_message = ">>> RECORDING ADDED to: "
|
5406
5744
|
star_len = len(rec_message) + len(file_path)
|
5407
|
-
|
5745
|
+
with suppress(Exception):
|
5408
5746
|
terminal_size = os.get_terminal_size().columns
|
5409
5747
|
if terminal_size > 30 and star_len > terminal_size:
|
5410
5748
|
star_len = terminal_size
|
5411
|
-
except Exception:
|
5412
|
-
pass
|
5413
5749
|
spc = "\n"
|
5414
5750
|
if hasattr(self, "rec_print") and self.rec_print:
|
5415
5751
|
spc = ""
|
@@ -5515,16 +5851,17 @@ class BaseCase(unittest.TestCase):
|
|
5515
5851
|
print("Created recordings/features/steps/imported.py")
|
5516
5852
|
|
5517
5853
|
def bring_active_window_to_front(self):
|
5518
|
-
"""Brings the active browser window to the front.
|
5519
|
-
|
5854
|
+
"""Brings the active browser window to the front (on top).
|
5855
|
+
Useful when multiple drivers are being used at the same time."""
|
5520
5856
|
self.__check_scope()
|
5521
|
-
|
5857
|
+
if self.__is_cdp_swap_needed():
|
5858
|
+
self.cdp.bring_active_window_to_front()
|
5859
|
+
return
|
5860
|
+
with suppress(Exception):
|
5522
5861
|
if not self.__is_in_frame():
|
5523
5862
|
# Only bring the window to the front if not in a frame
|
5524
5863
|
# because the driver resets itself to default content.
|
5525
5864
|
self.switch_to_window(self.driver.current_window_handle)
|
5526
|
-
except Exception:
|
5527
|
-
pass
|
5528
5865
|
|
5529
5866
|
def bring_to_front(self, selector, by="css selector"):
|
5530
5867
|
"""Updates the Z-index of a page element to bring it into view.
|
@@ -5554,7 +5891,7 @@ class BaseCase(unittest.TestCase):
|
|
5554
5891
|
def highlight_click(
|
5555
5892
|
self, selector, by="css selector", loops=3, scroll=True, timeout=None,
|
5556
5893
|
):
|
5557
|
-
"""Highlights the element and then clicks it."""
|
5894
|
+
"""Highlights the element, and then clicks it."""
|
5558
5895
|
self.__check_scope()
|
5559
5896
|
if not timeout:
|
5560
5897
|
timeout = settings.SMALL_TIMEOUT
|
@@ -5608,11 +5945,43 @@ class BaseCase(unittest.TestCase):
|
|
5608
5945
|
if self.is_element_visible(selector, by=by):
|
5609
5946
|
self.__highlight(selector, by=by, loops=loops, scroll=scroll)
|
5610
5947
|
|
5948
|
+
def __highlight_element(self, element, loops=None, scroll=True):
|
5949
|
+
self.__check_scope()
|
5950
|
+
if not loops:
|
5951
|
+
loops = settings.HIGHLIGHTS
|
5952
|
+
if scroll and self.browser != "safari":
|
5953
|
+
with suppress(Exception):
|
5954
|
+
self.__slow_scroll_to_element(element)
|
5955
|
+
if self.highlights:
|
5956
|
+
loops = self.highlights
|
5957
|
+
if self.browser == "ie":
|
5958
|
+
loops = 1 # Override previous setting because IE is slow
|
5959
|
+
loops = int(loops)
|
5960
|
+
if self.headless or self.headless2 or self.xvfb:
|
5961
|
+
# Headless modes have less need for highlighting elements.
|
5962
|
+
# However, highlight() may be used as a sleep alternative.
|
5963
|
+
loops = int(math.ceil(loops * 0.5))
|
5964
|
+
o_bs = "" # original_box_shadow
|
5965
|
+
try:
|
5966
|
+
style = element.get_attribute("style")
|
5967
|
+
except Exception:
|
5968
|
+
self.wait_for_ready_state_complete()
|
5969
|
+
time.sleep(0.12)
|
5970
|
+
style = element.get_attribute("style")
|
5971
|
+
if style:
|
5972
|
+
if "box-shadow: " in style:
|
5973
|
+
box_start = style.find("box-shadow: ")
|
5974
|
+
box_end = style.find(";", box_start) + 1
|
5975
|
+
original_box_shadow = style[box_start:box_end]
|
5976
|
+
o_bs = original_box_shadow
|
5977
|
+
self.__highlight_element_with_js(element, loops, o_bs)
|
5978
|
+
time.sleep(0.065)
|
5979
|
+
|
5611
5980
|
def __highlight(
|
5612
5981
|
self, selector, by="css selector", loops=None, scroll=True
|
5613
5982
|
):
|
5614
5983
|
"""This method uses fancy JavaScript to highlight an element.
|
5615
|
-
(
|
5984
|
+
(Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)"""
|
5616
5985
|
self.__check_scope()
|
5617
5986
|
selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
|
5618
5987
|
element = self.wait_for_element_visible(
|
@@ -5696,13 +6065,19 @@ class BaseCase(unittest.TestCase):
|
|
5696
6065
|
):
|
5697
6066
|
"""This method uses fancy JavaScript to highlight an element.
|
5698
6067
|
@Params
|
5699
|
-
selector - the selector of the element to find
|
6068
|
+
selector - the selector of the element to find (Accepts WebElement)
|
5700
6069
|
by - the type of selector to search by (Default: CSS)
|
5701
6070
|
loops - # of times to repeat the highlight animation
|
5702
6071
|
(Default: 4. Each loop lasts for about 0.2s)
|
5703
6072
|
scroll - the option to scroll to the element first (Default: True)
|
5704
6073
|
timeout - the time to wait for the element to appear """
|
5705
6074
|
self.__check_scope()
|
6075
|
+
if not self.__is_cdp_swap_needed():
|
6076
|
+
self._check_browser()
|
6077
|
+
self.__skip_if_esc()
|
6078
|
+
if isinstance(selector, WebElement):
|
6079
|
+
self.__highlight_element(selector, loops=loops, scroll=scroll)
|
6080
|
+
return
|
5706
6081
|
if not timeout:
|
5707
6082
|
timeout = settings.SMALL_TIMEOUT
|
5708
6083
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
@@ -5714,7 +6089,30 @@ class BaseCase(unittest.TestCase):
|
|
5714
6089
|
action = ["hi_li", selector, origin, time_stamp]
|
5715
6090
|
self.__extra_actions.append(action)
|
5716
6091
|
|
5717
|
-
def
|
6092
|
+
def highlight_elements(
|
6093
|
+
self,
|
6094
|
+
selector,
|
6095
|
+
by="css selector",
|
6096
|
+
loops=None,
|
6097
|
+
scroll=True,
|
6098
|
+
limit=0,
|
6099
|
+
):
|
6100
|
+
if not limit:
|
6101
|
+
limit = 0 # 0 means no limit
|
6102
|
+
limit = int(limit)
|
6103
|
+
count = 0
|
6104
|
+
elements = self.find_elements(selector, by=by)
|
6105
|
+
for element in elements:
|
6106
|
+
with suppress(Exception):
|
6107
|
+
if element.is_displayed():
|
6108
|
+
self.__highlight_element(
|
6109
|
+
element, loops=loops, scroll=scroll
|
6110
|
+
)
|
6111
|
+
count += 1
|
6112
|
+
if limit > 0 and count >= limit:
|
6113
|
+
break
|
6114
|
+
|
6115
|
+
def press_up_arrow(self, selector="body", times=1, by="css selector"):
|
5718
6116
|
"""Simulates pressing the UP Arrow on the keyboard.
|
5719
6117
|
By default, "html" will be used as the CSS Selector target.
|
5720
6118
|
You can specify how many times in-a-row the action happens."""
|
@@ -5736,7 +6134,7 @@ class BaseCase(unittest.TestCase):
|
|
5736
6134
|
if self.slow_mode:
|
5737
6135
|
time.sleep(0.1)
|
5738
6136
|
|
5739
|
-
def press_down_arrow(self, selector="
|
6137
|
+
def press_down_arrow(self, selector="body", times=1, by="css selector"):
|
5740
6138
|
"""Simulates pressing the DOWN Arrow on the keyboard.
|
5741
6139
|
By default, "html" will be used as the CSS Selector target.
|
5742
6140
|
You can specify how many times in-a-row the action happens."""
|
@@ -5758,7 +6156,7 @@ class BaseCase(unittest.TestCase):
|
|
5758
6156
|
if self.slow_mode:
|
5759
6157
|
time.sleep(0.1)
|
5760
6158
|
|
5761
|
-
def press_left_arrow(self, selector="
|
6159
|
+
def press_left_arrow(self, selector="body", times=1, by="css selector"):
|
5762
6160
|
"""Simulates pressing the LEFT Arrow on the keyboard.
|
5763
6161
|
By default, "html" will be used as the CSS Selector target.
|
5764
6162
|
You can specify how many times in-a-row the action happens."""
|
@@ -5780,7 +6178,7 @@ class BaseCase(unittest.TestCase):
|
|
5780
6178
|
if self.slow_mode:
|
5781
6179
|
time.sleep(0.1)
|
5782
6180
|
|
5783
|
-
def press_right_arrow(self, selector="
|
6181
|
+
def press_right_arrow(self, selector="body", times=1, by="css selector"):
|
5784
6182
|
"""Simulates pressing the RIGHT Arrow on the keyboard.
|
5785
6183
|
By default, "html" will be used as the CSS Selector target.
|
5786
6184
|
You can specify how many times in-a-row the action happens."""
|
@@ -5809,6 +6207,9 @@ class BaseCase(unittest.TestCase):
|
|
5809
6207
|
timeout = settings.SMALL_TIMEOUT
|
5810
6208
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
5811
6209
|
timeout = self.__get_new_timeout(timeout)
|
6210
|
+
if self.__is_cdp_swap_needed():
|
6211
|
+
self.cdp.scroll_into_view(selector)
|
6212
|
+
return
|
5812
6213
|
if self.demo_mode or self.slow_mode:
|
5813
6214
|
self.slow_scroll_to(selector, by=by, timeout=timeout)
|
5814
6215
|
return
|
@@ -5839,6 +6240,9 @@ class BaseCase(unittest.TestCase):
|
|
5839
6240
|
original_selector = selector
|
5840
6241
|
original_by = by
|
5841
6242
|
selector, by = self.__recalculate_selector(selector, by)
|
6243
|
+
if self.__is_cdp_swap_needed() and ":contains(" not in selector:
|
6244
|
+
self.cdp.scroll_into_view(selector)
|
6245
|
+
return
|
5842
6246
|
element = self.wait_for_element_visible(
|
5843
6247
|
original_selector, by=original_by, timeout=timeout
|
5844
6248
|
)
|
@@ -5876,30 +6280,45 @@ class BaseCase(unittest.TestCase):
|
|
5876
6280
|
timeout = settings.SMALL_TIMEOUT
|
5877
6281
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
5878
6282
|
timeout = self.__get_new_timeout(timeout)
|
6283
|
+
if self.__is_cdp_swap_needed():
|
6284
|
+
self.cdp.scroll_into_view(selector)
|
6285
|
+
return
|
5879
6286
|
element = self.wait_for_element_visible(selector, by, timeout=timeout)
|
5880
6287
|
self.execute_script("arguments[0].scrollIntoView();", element)
|
5881
6288
|
|
5882
6289
|
def scroll_to_top(self):
|
5883
6290
|
"""Scroll to the top of the page."""
|
5884
6291
|
self.__check_scope()
|
6292
|
+
if self.__is_cdp_swap_needed():
|
6293
|
+
self.cdp.scroll_to_top()
|
6294
|
+
return
|
5885
6295
|
scroll_script = "window.scrollTo(0, 0);"
|
5886
|
-
|
6296
|
+
with suppress(Exception):
|
5887
6297
|
self.execute_script(scroll_script)
|
5888
6298
|
time.sleep(0.012)
|
5889
|
-
return True
|
5890
|
-
except Exception:
|
5891
|
-
return False
|
5892
6299
|
|
5893
6300
|
def scroll_to_bottom(self):
|
5894
6301
|
"""Scroll to the bottom of the page."""
|
5895
6302
|
self.__check_scope()
|
6303
|
+
if self.__is_cdp_swap_needed():
|
6304
|
+
self.cdp.scroll_to_bottom()
|
6305
|
+
return
|
5896
6306
|
scroll_script = "window.scrollTo(0, 10000);"
|
5897
|
-
|
6307
|
+
with suppress(Exception):
|
6308
|
+
self.execute_script(scroll_script)
|
6309
|
+
time.sleep(0.012)
|
6310
|
+
|
6311
|
+
def scroll_to_y(self, y):
|
6312
|
+
"""Scroll to y position on the page."""
|
6313
|
+
self.__check_scope()
|
6314
|
+
y = int(y)
|
6315
|
+
if self.__is_cdp_swap_needed():
|
6316
|
+
self.cdp.scroll_to_y(y)
|
6317
|
+
return
|
6318
|
+
scroll_script = "window.scrollTo(0, %s);" % y
|
6319
|
+
with suppress(Exception):
|
5898
6320
|
self.execute_script(scroll_script)
|
5899
6321
|
time.sleep(0.012)
|
5900
|
-
return True
|
5901
|
-
except Exception:
|
5902
|
-
return False
|
5903
6322
|
|
5904
6323
|
def click_xpath(self, xpath):
|
5905
6324
|
"""Technically, self.click() automatically detects xpath selectors,
|
@@ -5918,6 +6337,9 @@ class BaseCase(unittest.TestCase):
|
|
5918
6337
|
Can be used to click hidden / invisible elements.
|
5919
6338
|
If "all_matches" is False, only the first match is clicked.
|
5920
6339
|
If "scroll" is False, won't scroll unless running in Demo Mode."""
|
6340
|
+
if self.__is_cdp_swap_needed():
|
6341
|
+
self.cdp.click(selector, timeout=timeout)
|
6342
|
+
return
|
5921
6343
|
self.wait_for_ready_state_complete()
|
5922
6344
|
if not timeout or timeout is True:
|
5923
6345
|
timeout = settings.SMALL_TIMEOUT
|
@@ -5957,10 +6379,8 @@ class BaseCase(unittest.TestCase):
|
|
5957
6379
|
time_stamp = 0
|
5958
6380
|
action = ["", "", "", time_stamp]
|
5959
6381
|
pre_action_url = None
|
5960
|
-
|
6382
|
+
with suppress(Exception):
|
5961
6383
|
pre_action_url = self.driver.current_url
|
5962
|
-
except Exception:
|
5963
|
-
pass
|
5964
6384
|
pre_window_count = len(self.driver.window_handles)
|
5965
6385
|
if self.recorder_mode and not self.__dont_record_js_click:
|
5966
6386
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6062,10 +6482,8 @@ class BaseCase(unittest.TestCase):
|
|
6062
6482
|
# If a click closes the active window,
|
6063
6483
|
# switch to the last one if it exists.
|
6064
6484
|
self.switch_to_window(-1)
|
6065
|
-
|
6485
|
+
with suppress(Exception):
|
6066
6486
|
self.wait_for_ready_state_complete()
|
6067
|
-
except Exception:
|
6068
|
-
pass
|
6069
6487
|
self.__demo_mode_pause_if_active()
|
6070
6488
|
|
6071
6489
|
def js_click_if_present(self, selector, by="css selector", timeout=0):
|
@@ -6077,10 +6495,8 @@ class BaseCase(unittest.TestCase):
|
|
6077
6495
|
if self.is_element_present(selector, by=by):
|
6078
6496
|
self.js_click(selector, by=by)
|
6079
6497
|
elif timeout > 0:
|
6080
|
-
|
6498
|
+
with suppress(Exception):
|
6081
6499
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
6082
|
-
except Exception:
|
6083
|
-
pass
|
6084
6500
|
if self.is_element_present(selector, by=by):
|
6085
6501
|
self.js_click(selector, by=by)
|
6086
6502
|
|
@@ -6093,10 +6509,8 @@ class BaseCase(unittest.TestCase):
|
|
6093
6509
|
if self.is_element_visible(selector, by=by):
|
6094
6510
|
self.js_click(selector, by=by)
|
6095
6511
|
elif timeout > 0:
|
6096
|
-
|
6512
|
+
with suppress(Exception):
|
6097
6513
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
6098
|
-
except Exception:
|
6099
|
-
pass
|
6100
6514
|
if self.is_element_visible(selector, by=by):
|
6101
6515
|
self.js_click(selector, by=by)
|
6102
6516
|
|
@@ -6189,13 +6603,11 @@ class BaseCase(unittest.TestCase):
|
|
6189
6603
|
"""Hide the first element on the page that matches the selector."""
|
6190
6604
|
self.__check_scope()
|
6191
6605
|
element = None
|
6192
|
-
|
6606
|
+
with suppress(Exception):
|
6193
6607
|
self.wait_for_element_visible("body", timeout=1.5)
|
6194
6608
|
element = self.wait_for_element_present(
|
6195
6609
|
selector, by=by, timeout=0.5
|
6196
6610
|
)
|
6197
|
-
except Exception:
|
6198
|
-
pass
|
6199
6611
|
selector, by = self.__recalculate_selector(selector, by)
|
6200
6612
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6201
6613
|
if ":contains(" in css_selector and element:
|
@@ -6221,10 +6633,8 @@ class BaseCase(unittest.TestCase):
|
|
6221
6633
|
def hide_elements(self, selector, by="css selector"):
|
6222
6634
|
"""Hide all elements on the page that match the selector."""
|
6223
6635
|
self.__check_scope()
|
6224
|
-
|
6636
|
+
with suppress(Exception):
|
6225
6637
|
self.wait_for_element_visible("body", timeout=1.5)
|
6226
|
-
except Exception:
|
6227
|
-
pass
|
6228
6638
|
selector, by = self.__recalculate_selector(selector, by)
|
6229
6639
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6230
6640
|
if ":contains(" in css_selector:
|
@@ -6247,11 +6657,9 @@ class BaseCase(unittest.TestCase):
|
|
6247
6657
|
"""Show the first element on the page that matches the selector."""
|
6248
6658
|
self.__check_scope()
|
6249
6659
|
element = None
|
6250
|
-
|
6660
|
+
with suppress(Exception):
|
6251
6661
|
self.wait_for_element_visible("body", timeout=1.5)
|
6252
6662
|
element = self.wait_for_element_present(selector, by=by, timeout=1)
|
6253
|
-
except Exception:
|
6254
|
-
pass
|
6255
6663
|
selector, by = self.__recalculate_selector(selector, by)
|
6256
6664
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6257
6665
|
if ":contains(" in css_selector and element:
|
@@ -6277,10 +6685,8 @@ class BaseCase(unittest.TestCase):
|
|
6277
6685
|
def show_elements(self, selector, by="css selector"):
|
6278
6686
|
"""Show all elements on the page that match the selector."""
|
6279
6687
|
self.__check_scope()
|
6280
|
-
|
6688
|
+
with suppress(Exception):
|
6281
6689
|
self.wait_for_element_visible("body", timeout=1.5)
|
6282
|
-
except Exception:
|
6283
|
-
pass
|
6284
6690
|
selector, by = self.__recalculate_selector(selector, by)
|
6285
6691
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6286
6692
|
if ":contains(" in css_selector:
|
@@ -6302,14 +6708,15 @@ class BaseCase(unittest.TestCase):
|
|
6302
6708
|
def remove_element(self, selector, by="css selector"):
|
6303
6709
|
"""Remove the first element on the page that matches the selector."""
|
6304
6710
|
self.__check_scope()
|
6711
|
+
if self.__is_cdp_swap_needed():
|
6712
|
+
self.cdp.remove_element(selector)
|
6713
|
+
return
|
6305
6714
|
element = None
|
6306
|
-
|
6715
|
+
with suppress(Exception):
|
6307
6716
|
self.wait_for_element_visible("body", timeout=1.5)
|
6308
6717
|
element = self.wait_for_element_present(
|
6309
6718
|
selector, by=by, timeout=0.5
|
6310
6719
|
)
|
6311
|
-
except Exception:
|
6312
|
-
pass
|
6313
6720
|
selector, by = self.__recalculate_selector(selector, by)
|
6314
6721
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6315
6722
|
if ":contains(" in css_selector and element:
|
@@ -6335,10 +6742,11 @@ class BaseCase(unittest.TestCase):
|
|
6335
6742
|
def remove_elements(self, selector, by="css selector"):
|
6336
6743
|
"""Remove all elements on the page that match the selector."""
|
6337
6744
|
self.__check_scope()
|
6338
|
-
|
6745
|
+
if self.__is_cdp_swap_needed():
|
6746
|
+
self.cdp.remove_elements(selector)
|
6747
|
+
return
|
6748
|
+
with suppress(Exception):
|
6339
6749
|
self.wait_for_element_visible("body", timeout=1.5)
|
6340
|
-
except Exception:
|
6341
|
-
pass
|
6342
6750
|
selector, by = self.__recalculate_selector(selector, by)
|
6343
6751
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6344
6752
|
if ":contains(" in css_selector:
|
@@ -6403,10 +6811,8 @@ class BaseCase(unittest.TestCase):
|
|
6403
6811
|
$elements[index].setAttribute('class', new_class);}"""
|
6404
6812
|
% css_selector
|
6405
6813
|
)
|
6406
|
-
|
6814
|
+
with suppress(Exception):
|
6407
6815
|
self.execute_script(script)
|
6408
|
-
except Exception:
|
6409
|
-
pass
|
6410
6816
|
if self.recorder_mode and self.__current_url_is_recordable():
|
6411
6817
|
if self.get_session_storage_item("pause_recorder") == "no":
|
6412
6818
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6424,10 +6830,8 @@ class BaseCase(unittest.TestCase):
|
|
6424
6830
|
self.is_chromium()
|
6425
6831
|
and self.driver.current_url.startswith("http")
|
6426
6832
|
):
|
6427
|
-
|
6833
|
+
with suppress(Exception):
|
6428
6834
|
self.driver.execute_script("window.onbeforeunload=null;")
|
6429
|
-
except Exception:
|
6430
|
-
pass
|
6431
6835
|
|
6432
6836
|
def get_domain_url(self, url):
|
6433
6837
|
self.__check_scope()
|
@@ -6443,15 +6847,12 @@ class BaseCase(unittest.TestCase):
|
|
6443
6847
|
from bs4 import BeautifulSoup
|
6444
6848
|
|
6445
6849
|
if not source:
|
6446
|
-
|
6850
|
+
with suppress(Exception):
|
6447
6851
|
self.wait_for_element_visible(
|
6448
6852
|
"body", timeout=settings.MINI_TIMEOUT
|
6449
6853
|
)
|
6450
|
-
except Exception:
|
6451
|
-
pass
|
6452
6854
|
source = self.get_page_source()
|
6453
|
-
|
6454
|
-
return soup
|
6855
|
+
return BeautifulSoup(source, "html.parser")
|
6455
6856
|
|
6456
6857
|
def get_unique_links(self):
|
6457
6858
|
"""Get all unique links in the html of the page source.
|
@@ -6462,19 +6863,16 @@ class BaseCase(unittest.TestCase):
|
|
6462
6863
|
time.sleep(0.08)
|
6463
6864
|
if self.undetectable:
|
6464
6865
|
time.sleep(0.02)
|
6465
|
-
|
6866
|
+
with suppress(Exception):
|
6466
6867
|
self.wait_for_element_present("body", timeout=1.5)
|
6467
6868
|
self.wait_for_element_visible("body", timeout=1.5)
|
6468
|
-
except Exception:
|
6469
|
-
pass
|
6470
6869
|
if self.__needs_minimum_wait():
|
6471
6870
|
time.sleep(0.25)
|
6472
6871
|
if self.undetectable:
|
6473
6872
|
time.sleep(0.123)
|
6474
6873
|
soup = self.get_beautiful_soup(self.get_page_source())
|
6475
6874
|
page_url = self.get_current_url()
|
6476
|
-
|
6477
|
-
return links
|
6875
|
+
return page_utils._get_unique_links(page_url, soup)
|
6478
6876
|
|
6479
6877
|
def get_link_status_code(
|
6480
6878
|
self,
|
@@ -6493,13 +6891,12 @@ class BaseCase(unittest.TestCase):
|
|
6493
6891
|
timeout = self.__requests_timeout
|
6494
6892
|
if timeout < 1:
|
6495
6893
|
timeout = 1
|
6496
|
-
|
6894
|
+
return page_utils._get_link_status_code(
|
6497
6895
|
link,
|
6498
6896
|
allow_redirects=allow_redirects,
|
6499
6897
|
timeout=timeout,
|
6500
6898
|
verify=verify,
|
6501
6899
|
)
|
6502
|
-
return status_code
|
6503
6900
|
|
6504
6901
|
def assert_link_status_code_is_not_404(self, link):
|
6505
6902
|
status_code = str(self.get_link_status_code(link))
|
@@ -6530,6 +6927,7 @@ class BaseCase(unittest.TestCase):
|
|
6530
6927
|
for link in all_links:
|
6531
6928
|
if (
|
6532
6929
|
"data:" not in link
|
6930
|
+
and "tel:" not in link
|
6533
6931
|
and "mailto:" not in link
|
6534
6932
|
and "javascript:" not in link
|
6535
6933
|
and "://fonts.gstatic.com" not in link
|
@@ -6663,18 +7061,19 @@ class BaseCase(unittest.TestCase):
|
|
6663
7061
|
constants.PipInstall.FINDLOCK
|
6664
7062
|
)
|
6665
7063
|
with pip_find_lock:
|
6666
|
-
|
6667
|
-
|
6668
|
-
|
6669
|
-
):
|
7064
|
+
with suppress(Exception):
|
7065
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7066
|
+
if sys.version_info < (3, 9):
|
6670
7067
|
# Fix bug in newer cryptography for Python 3.7 and 3.8:
|
6671
7068
|
# "pyo3_runtime.PanicException: Python API call failed"
|
6672
7069
|
try:
|
6673
7070
|
import cryptography
|
6674
7071
|
if cryptography.__version__ != "39.0.2":
|
7072
|
+
del cryptography # To get newer ver
|
6675
7073
|
shared_utils.pip_install(
|
6676
7074
|
"cryptography", version="39.0.2"
|
6677
7075
|
)
|
7076
|
+
import cryptography
|
6678
7077
|
except Exception:
|
6679
7078
|
shared_utils.pip_install(
|
6680
7079
|
"cryptography", version="39.0.2"
|
@@ -6682,12 +7081,7 @@ class BaseCase(unittest.TestCase):
|
|
6682
7081
|
try:
|
6683
7082
|
from pdfminer.high_level import extract_text
|
6684
7083
|
except Exception:
|
6685
|
-
|
6686
|
-
shared_utils.pip_install(
|
6687
|
-
"pdfminer.six", version="20221105"
|
6688
|
-
)
|
6689
|
-
else:
|
6690
|
-
shared_utils.pip_install("pdfminer.six")
|
7084
|
+
shared_utils.pip_install("pdfminer.six")
|
6691
7085
|
from pdfminer.high_level import extract_text
|
6692
7086
|
if not password:
|
6693
7087
|
password = ""
|
@@ -6735,8 +7129,7 @@ class BaseCase(unittest.TestCase):
|
|
6735
7129
|
pdf_text = self.__fix_unicode_conversion(pdf_text)
|
6736
7130
|
if wrap:
|
6737
7131
|
pdf_text = pdf_text.replace(" \n", " ")
|
6738
|
-
|
6739
|
-
return pdf_text
|
7132
|
+
return pdf_text.strip()
|
6740
7133
|
|
6741
7134
|
def assert_pdf_text(
|
6742
7135
|
self,
|
@@ -6808,10 +7201,8 @@ class BaseCase(unittest.TestCase):
|
|
6808
7201
|
if len(folder) < 1:
|
6809
7202
|
raise Exception("Minimum folder name length = 1.")
|
6810
7203
|
if not os.path.exists(folder):
|
6811
|
-
|
7204
|
+
with suppress(Exception):
|
6812
7205
|
os.makedirs(folder)
|
6813
|
-
except Exception:
|
6814
|
-
pass
|
6815
7206
|
|
6816
7207
|
def choose_file(
|
6817
7208
|
self, selector, file_path, by="css selector", timeout=None
|
@@ -6851,10 +7242,8 @@ class BaseCase(unittest.TestCase):
|
|
6851
7242
|
self.__scroll_to_element(element, selector, by)
|
6852
7243
|
pre_action_url = None
|
6853
7244
|
if self.demo_mode:
|
6854
|
-
|
7245
|
+
with suppress(Exception):
|
6855
7246
|
pre_action_url = self.driver.current_url
|
6856
|
-
except Exception:
|
6857
|
-
pass
|
6858
7247
|
if self.recorder_mode and self.__current_url_is_recordable():
|
6859
7248
|
if self.get_session_storage_item("pause_recorder") == "no":
|
6860
7249
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6924,6 +7313,8 @@ class BaseCase(unittest.TestCase):
|
|
6924
7313
|
constants.PipInstall.FINDLOCK
|
6925
7314
|
)
|
6926
7315
|
with pip_find_lock:
|
7316
|
+
with suppress(Exception):
|
7317
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
6927
7318
|
try:
|
6928
7319
|
from PIL import Image, ImageDraw
|
6929
7320
|
except Exception:
|
@@ -6969,6 +7360,10 @@ class BaseCase(unittest.TestCase):
|
|
6969
7360
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
6970
7361
|
)
|
6971
7362
|
with download_file_lock:
|
7363
|
+
with suppress(Exception):
|
7364
|
+
shared_utils.make_writable(
|
7365
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7366
|
+
)
|
6972
7367
|
if not destination_folder:
|
6973
7368
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
6974
7369
|
if not os.path.exists(destination_folder):
|
@@ -6989,6 +7384,10 @@ class BaseCase(unittest.TestCase):
|
|
6989
7384
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
6990
7385
|
)
|
6991
7386
|
with download_file_lock:
|
7387
|
+
with suppress(Exception):
|
7388
|
+
shared_utils.make_writable(
|
7389
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7390
|
+
)
|
6992
7391
|
if not destination_folder:
|
6993
7392
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
6994
7393
|
if not os.path.exists(destination_folder):
|
@@ -7094,6 +7493,8 @@ class BaseCase(unittest.TestCase):
|
|
7094
7493
|
constants.MultiBrowser.FILE_IO_LOCK
|
7095
7494
|
)
|
7096
7495
|
with file_io_lock:
|
7496
|
+
with suppress(Exception):
|
7497
|
+
shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
|
7097
7498
|
with open(fpath, "r") as f:
|
7098
7499
|
data = f.read().strip()
|
7099
7500
|
return data
|
@@ -7142,10 +7543,8 @@ class BaseCase(unittest.TestCase):
|
|
7142
7543
|
Those paths are usually the same. (browser-dependent)."""
|
7143
7544
|
if self.is_downloaded_file_present(file, browser=browser):
|
7144
7545
|
file_path = self.get_path_of_downloaded_file(file, browser=browser)
|
7145
|
-
|
7546
|
+
with suppress(Exception):
|
7146
7547
|
os.remove(file_path)
|
7147
|
-
except Exception:
|
7148
|
-
pass
|
7149
7548
|
|
7150
7549
|
def delete_downloaded_file(self, file, browser=False):
|
7151
7550
|
"""Same as self.delete_downloaded_file_if_present()
|
@@ -7162,10 +7561,8 @@ class BaseCase(unittest.TestCase):
|
|
7162
7561
|
Those paths are usually the same. (browser-dependent)."""
|
7163
7562
|
if self.is_downloaded_file_present(file, browser=browser):
|
7164
7563
|
file_path = self.get_path_of_downloaded_file(file, browser=browser)
|
7165
|
-
|
7564
|
+
with suppress(Exception):
|
7166
7565
|
os.remove(file_path)
|
7167
|
-
except Exception:
|
7168
|
-
pass
|
7169
7566
|
|
7170
7567
|
def assert_downloaded_file(self, file, timeout=None, browser=False):
|
7171
7568
|
"""Asserts that the file exists in SeleniumBase's [Downloads Folder].
|
@@ -7222,13 +7619,11 @@ class BaseCase(unittest.TestCase):
|
|
7222
7619
|
self.__extra_actions.append(action)
|
7223
7620
|
if self.demo_mode:
|
7224
7621
|
messenger_post = "<b>ASSERT DOWNLOADED FILE</b>: [%s]" % file
|
7225
|
-
|
7622
|
+
with suppress(Exception):
|
7226
7623
|
js_utils.activate_jquery(self.driver)
|
7227
7624
|
js_utils.post_messenger_success_message(
|
7228
7625
|
self.driver, messenger_post, self.message_duration
|
7229
7626
|
)
|
7230
|
-
except Exception:
|
7231
|
-
pass
|
7232
7627
|
|
7233
7628
|
def assert_downloaded_file_regex(self, regex, timeout=None, browser=False):
|
7234
7629
|
"""Assert the filename regex exists in SeleniumBase's Downloads Folder.
|
@@ -7277,13 +7672,11 @@ class BaseCase(unittest.TestCase):
|
|
7277
7672
|
messenger_post = (
|
7278
7673
|
"<b>ASSERT DOWNLOADED FILE REGEX</b>: [%s]" % regex
|
7279
7674
|
)
|
7280
|
-
|
7675
|
+
with suppress(Exception):
|
7281
7676
|
js_utils.activate_jquery(self.driver)
|
7282
7677
|
js_utils.post_messenger_success_message(
|
7283
7678
|
self.driver, messenger_post, self.message_duration
|
7284
7679
|
)
|
7285
|
-
except Exception:
|
7286
|
-
pass
|
7287
7680
|
|
7288
7681
|
def assert_data_in_downloaded_file(
|
7289
7682
|
self, data, file, timeout=None, browser=False
|
@@ -7302,37 +7695,37 @@ class BaseCase(unittest.TestCase):
|
|
7302
7695
|
|
7303
7696
|
def assert_true(self, expr, msg=None):
|
7304
7697
|
"""Asserts that the expression is True.
|
7305
|
-
|
7698
|
+
Raises an exception if the statement if False."""
|
7306
7699
|
self.assertTrue(expr, msg=msg)
|
7307
7700
|
|
7308
7701
|
def assert_false(self, expr, msg=None):
|
7309
7702
|
"""Asserts that the expression is False.
|
7310
|
-
|
7703
|
+
Raises an exception if the statement if True."""
|
7311
7704
|
self.assertFalse(expr, msg=msg)
|
7312
7705
|
|
7313
7706
|
def assert_equal(self, first, second, msg=None):
|
7314
7707
|
"""Asserts that the two values are equal.
|
7315
|
-
|
7708
|
+
Raises an exception if the values are not equal."""
|
7316
7709
|
self.assertEqual(first, second, msg=msg)
|
7317
7710
|
|
7318
7711
|
def assert_not_equal(self, first, second, msg=None):
|
7319
7712
|
"""Asserts that the two values are not equal.
|
7320
|
-
|
7713
|
+
Raises an exception if the values are equal."""
|
7321
7714
|
self.assertNotEqual(first, second, msg=msg)
|
7322
7715
|
|
7323
7716
|
def assert_in(self, first, second, msg=None):
|
7324
7717
|
"""Asserts that the first string is in the second string.
|
7325
|
-
|
7718
|
+
Raises an exception if the first string is not in the second."""
|
7326
7719
|
self.assertIn(first, second, msg=msg)
|
7327
7720
|
|
7328
7721
|
def assert_not_in(self, first, second, msg=None):
|
7329
7722
|
"""Asserts that the first string is not in the second string.
|
7330
|
-
|
7723
|
+
Raises an exception if the first string is in the second string."""
|
7331
7724
|
self.assertNotIn(first, second, msg=msg)
|
7332
7725
|
|
7333
7726
|
def assert_raises(self, *args, **kwargs):
|
7334
7727
|
"""Asserts that the following block of code raises an exception.
|
7335
|
-
|
7728
|
+
Raises an exception if the block of code has no exception.
|
7336
7729
|
Usage Example =>
|
7337
7730
|
# Verify that the expected exception is raised.
|
7338
7731
|
with self.assert_raises(Exception):
|
@@ -7352,7 +7745,10 @@ class BaseCase(unittest.TestCase):
|
|
7352
7745
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
7353
7746
|
timeout = self.__get_new_timeout(timeout)
|
7354
7747
|
selector, by = self.__recalculate_selector(selector, by)
|
7355
|
-
if self.
|
7748
|
+
if self.__is_cdp_swap_needed():
|
7749
|
+
self.cdp.assert_element_attribute(selector, attribute, value)
|
7750
|
+
return
|
7751
|
+
elif self.__is_shadow_selector(selector):
|
7356
7752
|
return self.__wait_for_shadow_attribute_present(
|
7357
7753
|
selector, attribute, value=value, timeout=timeout
|
7358
7754
|
)
|
@@ -7377,6 +7773,9 @@ class BaseCase(unittest.TestCase):
|
|
7377
7773
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
7378
7774
|
timeout = self.__get_new_timeout(timeout)
|
7379
7775
|
selector, by = self.__recalculate_selector(selector, by)
|
7776
|
+
if self.__is_cdp_swap_needed():
|
7777
|
+
self.cdp.assert_element_attribute(selector, attribute, value)
|
7778
|
+
return
|
7380
7779
|
self.wait_for_attribute(
|
7381
7780
|
selector, attribute, value=value, by=by, timeout=timeout
|
7382
7781
|
)
|
@@ -7426,6 +7825,9 @@ class BaseCase(unittest.TestCase):
|
|
7426
7825
|
but then the title switches over to the actual page title.
|
7427
7826
|
In Recorder Mode, this assertion is skipped because the Recorder
|
7428
7827
|
changes the page title to the selector of the hovered element."""
|
7828
|
+
if self.__is_cdp_swap_needed():
|
7829
|
+
self.cdp.assert_title(title)
|
7830
|
+
return
|
7429
7831
|
self.wait_for_ready_state_complete()
|
7430
7832
|
expected = title.strip()
|
7431
7833
|
actual = self.get_page_title().strip()
|
@@ -7472,6 +7874,9 @@ class BaseCase(unittest.TestCase):
|
|
7472
7874
|
but then the title switches over to the actual page title.
|
7473
7875
|
In Recorder Mode, this assertion is skipped because the Recorder
|
7474
7876
|
changes the page title to the selector of the hovered element."""
|
7877
|
+
if self.__is_cdp_swap_needed():
|
7878
|
+
self.cdp.assert_title_contains(substring)
|
7879
|
+
return
|
7475
7880
|
self.wait_for_ready_state_complete()
|
7476
7881
|
expected = substring.strip()
|
7477
7882
|
actual = self.get_page_title().strip()
|
@@ -7515,6 +7920,9 @@ class BaseCase(unittest.TestCase):
|
|
7515
7920
|
|
7516
7921
|
def assert_url(self, url):
|
7517
7922
|
"""Asserts that the web page URL matches the expected URL."""
|
7923
|
+
if self.__is_cdp_swap_needed():
|
7924
|
+
self.cdp.assert_url(url)
|
7925
|
+
return
|
7518
7926
|
self.wait_for_ready_state_complete()
|
7519
7927
|
expected = url.strip()
|
7520
7928
|
actual = self.get_current_url().strip()
|
@@ -7550,6 +7958,9 @@ class BaseCase(unittest.TestCase):
|
|
7550
7958
|
|
7551
7959
|
def assert_url_contains(self, substring):
|
7552
7960
|
"""Asserts that the URL substring appears in the full URL."""
|
7961
|
+
if self.__is_cdp_swap_needed():
|
7962
|
+
self.cdp.assert_url_contains(substring)
|
7963
|
+
return
|
7553
7964
|
self.wait_for_ready_state_complete()
|
7554
7965
|
expected = substring.strip()
|
7555
7966
|
actual = self.get_current_url().strip()
|
@@ -7739,14 +8150,33 @@ class BaseCase(unittest.TestCase):
|
|
7739
8150
|
"""Return True if the url is a valid url."""
|
7740
8151
|
return page_utils.is_valid_url(url)
|
7741
8152
|
|
8153
|
+
def is_alert_present(self):
|
8154
|
+
try:
|
8155
|
+
self.driver.switch_to.alert
|
8156
|
+
return True
|
8157
|
+
except Exception:
|
8158
|
+
return False
|
8159
|
+
|
7742
8160
|
def is_online(self):
|
7743
8161
|
"""Return True if connected to the Internet."""
|
7744
|
-
|
7745
|
-
|
8162
|
+
if self.__is_cdp_swap_needed():
|
8163
|
+
return self.cdp.evaluate("navigator.onLine;")
|
8164
|
+
return self.execute_script("return navigator.onLine;")
|
8165
|
+
|
8166
|
+
def is_connected(self):
|
8167
|
+
"""
|
8168
|
+
Return True if WebDriver is connected to the browser.
|
8169
|
+
Note that the stealthy CDP-Driver isn't a WebDriver.
|
8170
|
+
In CDP Mode, the CDP-Driver controls the web browser.
|
8171
|
+
The CDP-Driver can be connected while WebDriver isn't.
|
8172
|
+
"""
|
8173
|
+
return self.driver.is_connected()
|
7746
8174
|
|
7747
8175
|
def is_chromium(self):
|
7748
8176
|
"""Return True if the browser is Chrome or Edge."""
|
7749
8177
|
self.__check_scope()
|
8178
|
+
if self.__is_cdp_swap_needed():
|
8179
|
+
return True
|
7750
8180
|
chromium = False
|
7751
8181
|
if (
|
7752
8182
|
"chrome" in self.driver.capabilities
|
@@ -7859,6 +8289,10 @@ class BaseCase(unittest.TestCase):
|
|
7859
8289
|
self.__check_scope()
|
7860
8290
|
if not timeout:
|
7861
8291
|
timeout = settings.SMALL_TIMEOUT
|
8292
|
+
if self.__is_cdp_swap_needed():
|
8293
|
+
mfa_code = self.get_mfa_code(totp_key)
|
8294
|
+
self.cdp.type(selector, mfa_code + "\n", timeout=timeout)
|
8295
|
+
return
|
7862
8296
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
7863
8297
|
if self.recorder_mode and self.__current_url_is_recordable():
|
7864
8298
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -7884,27 +8318,7 @@ class BaseCase(unittest.TestCase):
|
|
7884
8318
|
jQuery commands require a CSS_SELECTOR for finding elements.
|
7885
8319
|
This method should only be used for jQuery/JavaScript actions.
|
7886
8320
|
Pure JavaScript doesn't support using a:contains("LINK_TEXT")."""
|
7887
|
-
|
7888
|
-
return selector
|
7889
|
-
elif by == By.ID:
|
7890
|
-
return "#%s" % selector
|
7891
|
-
elif by == By.CLASS_NAME:
|
7892
|
-
return ".%s" % selector
|
7893
|
-
elif by == By.NAME:
|
7894
|
-
return '[name="%s"]' % selector
|
7895
|
-
elif by == By.TAG_NAME:
|
7896
|
-
return selector
|
7897
|
-
elif by == By.XPATH:
|
7898
|
-
return self.convert_xpath_to_css(selector)
|
7899
|
-
elif by == By.LINK_TEXT:
|
7900
|
-
return 'a:contains("%s")' % selector
|
7901
|
-
elif by == By.PARTIAL_LINK_TEXT:
|
7902
|
-
return 'a:contains("%s")' % selector
|
7903
|
-
else:
|
7904
|
-
raise Exception(
|
7905
|
-
"Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"
|
7906
|
-
% (selector, by)
|
7907
|
-
)
|
8321
|
+
return js_utils.convert_to_css_selector(selector, by)
|
7908
8322
|
|
7909
8323
|
def set_value(
|
7910
8324
|
self, selector, text, by="css selector", timeout=None, scroll=True
|
@@ -7916,6 +8330,9 @@ class BaseCase(unittest.TestCase):
|
|
7916
8330
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
7917
8331
|
timeout = self.__get_new_timeout(timeout)
|
7918
8332
|
selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
|
8333
|
+
if self.__is_cdp_swap_needed():
|
8334
|
+
self.cdp.set_value(selector, text)
|
8335
|
+
return
|
7919
8336
|
self.wait_for_ready_state_complete()
|
7920
8337
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
7921
8338
|
original_selector = selector
|
@@ -7973,17 +8390,15 @@ class BaseCase(unittest.TestCase):
|
|
7973
8390
|
else:
|
7974
8391
|
if the_type == "range" and ":contains\\(" not in css_selector:
|
7975
8392
|
# Some input sliders need a mouse event to trigger listeners.
|
7976
|
-
|
8393
|
+
with suppress(Exception):
|
7977
8394
|
mouse_move_script = (
|
7978
8395
|
"""m_elm = document.querySelector('%s');"""
|
7979
8396
|
"""m_evt = new Event('mousemove');"""
|
7980
8397
|
"""m_elm.dispatchEvent(m_evt);""" % css_selector
|
7981
8398
|
)
|
7982
8399
|
self.execute_script(mouse_move_script)
|
7983
|
-
except Exception:
|
7984
|
-
pass
|
7985
8400
|
elif the_type == "range" and ":contains\\(" in css_selector:
|
7986
|
-
|
8401
|
+
with suppress(Exception):
|
7987
8402
|
element = self.wait_for_element_present(
|
7988
8403
|
original_selector, by=by, timeout=1
|
7989
8404
|
)
|
@@ -7993,8 +8408,6 @@ class BaseCase(unittest.TestCase):
|
|
7993
8408
|
"""m_elm.dispatchEvent(m_evt);"""
|
7994
8409
|
)
|
7995
8410
|
self.execute_script(mouse_move_script, element)
|
7996
|
-
except Exception:
|
7997
|
-
pass
|
7998
8411
|
self.__demo_mode_pause_if_active()
|
7999
8412
|
if not self.demo_mode and not self.slow_mode:
|
8000
8413
|
if self.__needs_minimum_wait():
|
@@ -8014,13 +8427,11 @@ class BaseCase(unittest.TestCase):
|
|
8014
8427
|
text = self.__get_type_checked_text(text)
|
8015
8428
|
self.set_value(selector, text, by=by, timeout=timeout)
|
8016
8429
|
if not text.endswith("\n"):
|
8017
|
-
|
8430
|
+
with suppress(Exception):
|
8018
8431
|
element = page_actions.wait_for_element_present(
|
8019
8432
|
self.driver, selector, by, timeout=0.2
|
8020
8433
|
)
|
8021
8434
|
element.send_keys(" " + Keys.BACK_SPACE)
|
8022
|
-
except Exception:
|
8023
|
-
pass
|
8024
8435
|
|
8025
8436
|
def js_type(self, selector, text, by="css selector", timeout=None):
|
8026
8437
|
"""Same as self.js_update_text()
|
@@ -8140,13 +8551,11 @@ class BaseCase(unittest.TestCase):
|
|
8140
8551
|
)
|
8141
8552
|
element.send_keys(Keys.RETURN)
|
8142
8553
|
else:
|
8143
|
-
|
8554
|
+
with suppress(Exception):
|
8144
8555
|
element = self.wait_for_element_present(
|
8145
8556
|
original_selector, by=original_by, timeout=0.2
|
8146
8557
|
)
|
8147
8558
|
element.send_keys(" " + Keys.BACK_SPACE)
|
8148
|
-
except Exception:
|
8149
|
-
pass
|
8150
8559
|
self.__demo_mode_pause_if_active()
|
8151
8560
|
|
8152
8561
|
def jquery_type(self, selector, text, by="css selector", timeout=None):
|
@@ -8323,10 +8732,8 @@ class BaseCase(unittest.TestCase):
|
|
8323
8732
|
def get_recorded_console_logs(self):
|
8324
8733
|
"""Get console logs recorded after "start_recording_console_logs()"."""
|
8325
8734
|
logs = []
|
8326
|
-
|
8735
|
+
with suppress(Exception):
|
8327
8736
|
logs = self.execute_script("return console.logs;")
|
8328
|
-
except Exception:
|
8329
|
-
pass
|
8330
8737
|
return logs
|
8331
8738
|
|
8332
8739
|
############
|
@@ -8634,12 +9041,15 @@ class BaseCase(unittest.TestCase):
|
|
8634
9041
|
):
|
8635
9042
|
"""Same as self.wait_for_element()"""
|
8636
9043
|
self.__check_scope()
|
9044
|
+
self.__skip_if_esc()
|
8637
9045
|
if not timeout:
|
8638
9046
|
timeout = settings.LARGE_TIMEOUT
|
8639
9047
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
8640
9048
|
timeout = self.__get_new_timeout(timeout)
|
8641
9049
|
original_selector = selector
|
8642
9050
|
selector, by = self.__recalculate_selector(selector, by)
|
9051
|
+
if self.__is_cdp_swap_needed():
|
9052
|
+
return self.cdp.select(selector, timeout=timeout)
|
8643
9053
|
if self.__is_shadow_selector(selector):
|
8644
9054
|
return self.__get_shadow_element(selector, timeout)
|
8645
9055
|
return page_actions.wait_for_element_visible(
|
@@ -8661,7 +9071,9 @@ class BaseCase(unittest.TestCase):
|
|
8661
9071
|
timeout = self.__get_new_timeout(timeout)
|
8662
9072
|
original_selector = selector
|
8663
9073
|
selector, by = self.__recalculate_selector(selector, by)
|
8664
|
-
if self.
|
9074
|
+
if self.__is_cdp_swap_needed():
|
9075
|
+
return self.cdp.select(selector, timeout=timeout)
|
9076
|
+
elif self.__is_shadow_selector(selector):
|
8665
9077
|
# If a shadow selector, use visible instead of clickable
|
8666
9078
|
return self.__wait_for_shadow_element_visible(selector, timeout)
|
8667
9079
|
return page_actions.wait_for_element_clickable(
|
@@ -8687,6 +9099,9 @@ class BaseCase(unittest.TestCase):
|
|
8687
9099
|
timeout = self.__get_new_timeout(timeout)
|
8688
9100
|
original_selector = selector
|
8689
9101
|
selector, by = self.__recalculate_selector(selector, by)
|
9102
|
+
if self.__is_cdp_swap_needed():
|
9103
|
+
self.cdp.assert_element_absent(selector)
|
9104
|
+
return True
|
8690
9105
|
return page_actions.wait_for_element_absent(
|
8691
9106
|
self.driver,
|
8692
9107
|
selector,
|
@@ -8695,6 +9110,9 @@ class BaseCase(unittest.TestCase):
|
|
8695
9110
|
original_selector=original_selector,
|
8696
9111
|
)
|
8697
9112
|
|
9113
|
+
def select_all(self, selector, by="css selector", limit=0):
|
9114
|
+
return self.find_elements(selector, by=by, limit=limit)
|
9115
|
+
|
8698
9116
|
def assert_link(self, link_text, timeout=None):
|
8699
9117
|
"""Same as self.assert_link_text()"""
|
8700
9118
|
self.__check_scope()
|
@@ -8708,7 +9126,7 @@ class BaseCase(unittest.TestCase):
|
|
8708
9126
|
self, selector, by="css selector", timeout=None
|
8709
9127
|
):
|
8710
9128
|
"""Same as self.assert_element_absent()
|
8711
|
-
|
9129
|
+
Raises an exception if the element stays present.
|
8712
9130
|
A hidden element counts as a present element, which fails this assert.
|
8713
9131
|
If you want to assert that elements are hidden instead of nonexistent,
|
8714
9132
|
use assert_element_not_visible() instead.
|
@@ -8746,6 +9164,14 @@ class BaseCase(unittest.TestCase):
|
|
8746
9164
|
"""Same as self.delete_all_cookies()"""
|
8747
9165
|
self.delete_all_cookies()
|
8748
9166
|
|
9167
|
+
def delete_local_storage(self):
|
9168
|
+
"""Same as self.clear_local_storage()"""
|
9169
|
+
self.clear_local_storage()
|
9170
|
+
|
9171
|
+
def delete_session_storage(self):
|
9172
|
+
"""Same as clear_session_storage()"""
|
9173
|
+
self.clear_session_storage()
|
9174
|
+
|
8749
9175
|
def assert_no_broken_links(self, multithreaded=True):
|
8750
9176
|
"""Same as self.assert_no_404_errors()"""
|
8751
9177
|
self.assert_no_404_errors(multithreaded=multithreaded)
|
@@ -8761,11 +9187,10 @@ class BaseCase(unittest.TestCase):
|
|
8761
9187
|
def _check_browser(self):
|
8762
9188
|
"""This method raises an exception if the active window is closed.
|
8763
9189
|
(This provides a much cleaner exception message in this situation.)"""
|
9190
|
+
page_actions._reconnect_if_disconnected(self.driver)
|
8764
9191
|
active_window = None
|
8765
|
-
|
9192
|
+
with suppress(Exception):
|
8766
9193
|
active_window = self.driver.current_window_handle # Fails if None
|
8767
|
-
except Exception:
|
8768
|
-
pass
|
8769
9194
|
if not active_window:
|
8770
9195
|
raise NoSuchWindowException("Active window was already closed!")
|
8771
9196
|
|
@@ -8779,10 +9204,8 @@ class BaseCase(unittest.TestCase):
|
|
8779
9204
|
"""
|
8780
9205
|
if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
|
8781
9206
|
if not isinstance(msg, str):
|
8782
|
-
|
9207
|
+
with suppress(Exception):
|
8783
9208
|
msg = str(msg)
|
8784
|
-
except Exception:
|
8785
|
-
pass
|
8786
9209
|
sys.stderr.write(msg + "\n")
|
8787
9210
|
else:
|
8788
9211
|
print(msg)
|
@@ -9049,7 +9472,9 @@ class BaseCase(unittest.TestCase):
|
|
9049
9472
|
timeout = self.__get_new_timeout(timeout)
|
9050
9473
|
original_selector = selector
|
9051
9474
|
selector, by = self.__recalculate_selector(selector, by)
|
9052
|
-
if self.
|
9475
|
+
if self.__is_cdp_swap_needed():
|
9476
|
+
return self.cdp.select(selector, timeout=timeout)
|
9477
|
+
elif self.__is_shadow_selector(selector):
|
9053
9478
|
return self.__wait_for_shadow_element_present(selector, timeout)
|
9054
9479
|
return page_actions.wait_for_element_present(
|
9055
9480
|
self.driver,
|
@@ -9069,6 +9494,8 @@ class BaseCase(unittest.TestCase):
|
|
9069
9494
|
timeout = self.__get_new_timeout(timeout)
|
9070
9495
|
original_selector = selector
|
9071
9496
|
selector, by = self.__recalculate_selector(selector, by)
|
9497
|
+
if self.__is_cdp_swap_needed():
|
9498
|
+
return self.cdp.select(selector, timeout=timeout)
|
9072
9499
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9073
9500
|
if self.get_session_storage_item("pause_recorder") == "no":
|
9074
9501
|
if by == By.XPATH:
|
@@ -9110,6 +9537,8 @@ class BaseCase(unittest.TestCase):
|
|
9110
9537
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
9111
9538
|
timeout = self.__get_new_timeout(timeout)
|
9112
9539
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
9540
|
+
if self.__is_cdp_swap_needed():
|
9541
|
+
return self.cdp.select(css_selector, timeout=timeout)
|
9113
9542
|
return js_utils.wait_for_css_query_selector(
|
9114
9543
|
self.driver, css_selector, timeout
|
9115
9544
|
)
|
@@ -9129,6 +9558,9 @@ class BaseCase(unittest.TestCase):
|
|
9129
9558
|
if isinstance(selector, list):
|
9130
9559
|
self.assert_elements_present(selector, by=by, timeout=timeout)
|
9131
9560
|
return True
|
9561
|
+
if self.__is_cdp_swap_needed():
|
9562
|
+
self.cdp.assert_element_present(selector)
|
9563
|
+
return True
|
9132
9564
|
if self.__is_shadow_selector(selector):
|
9133
9565
|
self.__assert_shadow_element_present(selector)
|
9134
9566
|
return True
|
@@ -9196,13 +9628,16 @@ class BaseCase(unittest.TestCase):
|
|
9196
9628
|
|
9197
9629
|
def assert_element(self, selector, by="css selector", timeout=None):
|
9198
9630
|
"""Similar to wait_for_element_visible(), but returns nothing.
|
9199
|
-
As above,
|
9631
|
+
As above, raises an exception if nothing can be found.
|
9200
9632
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9201
9633
|
self.__check_scope()
|
9202
9634
|
if not timeout:
|
9203
9635
|
timeout = settings.SMALL_TIMEOUT
|
9204
9636
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9205
9637
|
timeout = self.__get_new_timeout(timeout)
|
9638
|
+
if self.__is_cdp_swap_needed():
|
9639
|
+
self.cdp.assert_element(selector)
|
9640
|
+
return True
|
9206
9641
|
if isinstance(selector, list):
|
9207
9642
|
self.assert_elements(selector, by=by, timeout=timeout)
|
9208
9643
|
return True
|
@@ -9236,7 +9671,7 @@ class BaseCase(unittest.TestCase):
|
|
9236
9671
|
self, selector, by="css selector", timeout=None
|
9237
9672
|
):
|
9238
9673
|
"""Same as self.assert_element()
|
9239
|
-
As above,
|
9674
|
+
As above, raises an exception if nothing can be found."""
|
9240
9675
|
self.__check_scope()
|
9241
9676
|
if not timeout:
|
9242
9677
|
timeout = settings.SMALL_TIMEOUT
|
@@ -9314,7 +9749,7 @@ class BaseCase(unittest.TestCase):
|
|
9314
9749
|
############
|
9315
9750
|
|
9316
9751
|
def wait_for_text_visible(
|
9317
|
-
self, text, selector="
|
9752
|
+
self, text, selector="body", by="css selector", timeout=None
|
9318
9753
|
):
|
9319
9754
|
self.__check_scope()
|
9320
9755
|
if not timeout:
|
@@ -9323,14 +9758,16 @@ class BaseCase(unittest.TestCase):
|
|
9323
9758
|
timeout = self.__get_new_timeout(timeout)
|
9324
9759
|
text = self.__get_type_checked_text(text)
|
9325
9760
|
selector, by = self.__recalculate_selector(selector, by)
|
9326
|
-
if self.
|
9761
|
+
if self.__is_cdp_swap_needed():
|
9762
|
+
return self.cdp.find_element(selector, timeout=timeout)
|
9763
|
+
elif self.__is_shadow_selector(selector):
|
9327
9764
|
return self.__wait_for_shadow_text_visible(text, selector, timeout)
|
9328
9765
|
return page_actions.wait_for_text_visible(
|
9329
9766
|
self.driver, text, selector, by, timeout
|
9330
9767
|
)
|
9331
9768
|
|
9332
9769
|
def wait_for_exact_text_visible(
|
9333
|
-
self, text, selector="
|
9770
|
+
self, text, selector="body", by="css selector", timeout=None
|
9334
9771
|
):
|
9335
9772
|
self.__check_scope()
|
9336
9773
|
if not timeout:
|
@@ -9347,7 +9784,7 @@ class BaseCase(unittest.TestCase):
|
|
9347
9784
|
)
|
9348
9785
|
|
9349
9786
|
def wait_for_non_empty_text_visible(
|
9350
|
-
self, selector="
|
9787
|
+
self, selector="body", by="css selector", timeout=None
|
9351
9788
|
):
|
9352
9789
|
"""Searches for any text in the element of the given selector.
|
9353
9790
|
Returns the element if it has visible text within the timeout.
|
@@ -9368,7 +9805,7 @@ class BaseCase(unittest.TestCase):
|
|
9368
9805
|
)
|
9369
9806
|
|
9370
9807
|
def wait_for_text(
|
9371
|
-
self, text, selector="
|
9808
|
+
self, text, selector="body", by="css selector", timeout=None
|
9372
9809
|
):
|
9373
9810
|
"""The shorter version of wait_for_text_visible()"""
|
9374
9811
|
self.__check_scope()
|
@@ -9381,7 +9818,7 @@ class BaseCase(unittest.TestCase):
|
|
9381
9818
|
)
|
9382
9819
|
|
9383
9820
|
def wait_for_exact_text(
|
9384
|
-
self, text, selector="
|
9821
|
+
self, text, selector="body", by="css selector", timeout=None
|
9385
9822
|
):
|
9386
9823
|
"""The shorter version of wait_for_exact_text_visible()"""
|
9387
9824
|
self.__check_scope()
|
@@ -9394,7 +9831,7 @@ class BaseCase(unittest.TestCase):
|
|
9394
9831
|
)
|
9395
9832
|
|
9396
9833
|
def wait_for_non_empty_text(
|
9397
|
-
self, selector="
|
9834
|
+
self, selector="body", by="css selector", timeout=None
|
9398
9835
|
):
|
9399
9836
|
"""The shorter version of wait_for_non_empty_text_visible()"""
|
9400
9837
|
self.__check_scope()
|
@@ -9407,7 +9844,7 @@ class BaseCase(unittest.TestCase):
|
|
9407
9844
|
)
|
9408
9845
|
|
9409
9846
|
def find_text(
|
9410
|
-
self, text, selector="
|
9847
|
+
self, text, selector="body", by="css selector", timeout=None
|
9411
9848
|
):
|
9412
9849
|
"""Same as wait_for_text_visible() - returns the element"""
|
9413
9850
|
self.__check_scope()
|
@@ -9420,7 +9857,7 @@ class BaseCase(unittest.TestCase):
|
|
9420
9857
|
)
|
9421
9858
|
|
9422
9859
|
def find_exact_text(
|
9423
|
-
self, text, selector="
|
9860
|
+
self, text, selector="body", by="css selector", timeout=None
|
9424
9861
|
):
|
9425
9862
|
"""Same as wait_for_exact_text_visible() - returns the element"""
|
9426
9863
|
self.__check_scope()
|
@@ -9433,7 +9870,7 @@ class BaseCase(unittest.TestCase):
|
|
9433
9870
|
)
|
9434
9871
|
|
9435
9872
|
def find_non_empty_text(
|
9436
|
-
self, selector="
|
9873
|
+
self, selector="body", by="css selector", timeout=None
|
9437
9874
|
):
|
9438
9875
|
"""Same as wait_for_non_empty_text_visible() - returns the element"""
|
9439
9876
|
self.__check_scope()
|
@@ -9446,7 +9883,7 @@ class BaseCase(unittest.TestCase):
|
|
9446
9883
|
)
|
9447
9884
|
|
9448
9885
|
def assert_text_visible(
|
9449
|
-
self, text, selector="
|
9886
|
+
self, text, selector="body", by="css selector", timeout=None
|
9450
9887
|
):
|
9451
9888
|
"""Same as assert_text()"""
|
9452
9889
|
self.__check_scope()
|
@@ -9457,11 +9894,12 @@ class BaseCase(unittest.TestCase):
|
|
9457
9894
|
return self.assert_text(text, selector, by=by, timeout=timeout)
|
9458
9895
|
|
9459
9896
|
def assert_text(
|
9460
|
-
self, text, selector="
|
9897
|
+
self, text, selector="body", by="css selector", timeout=None
|
9461
9898
|
):
|
9462
9899
|
"""Similar to wait_for_text_visible()
|
9463
9900
|
Raises an exception if the element or the text is not found.
|
9464
9901
|
The text only needs to be a subset within the complete text.
|
9902
|
+
The text can be a string or a list/tuple of text substrings.
|
9465
9903
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9466
9904
|
self.__check_scope()
|
9467
9905
|
if not timeout:
|
@@ -9470,26 +9908,50 @@ class BaseCase(unittest.TestCase):
|
|
9470
9908
|
timeout = self.__get_new_timeout(timeout)
|
9471
9909
|
original_selector = selector
|
9472
9910
|
selector, by = self.__recalculate_selector(selector, by)
|
9473
|
-
if
|
9911
|
+
if isinstance(text, (list, tuple)):
|
9912
|
+
text_list = text
|
9913
|
+
for _text in text_list:
|
9914
|
+
self.wait_for_text_visible(
|
9915
|
+
_text, selector, by=by, timeout=timeout
|
9916
|
+
)
|
9917
|
+
if self.demo_mode:
|
9918
|
+
a_t = "ASSERT TEXT"
|
9919
|
+
i_n = "in"
|
9920
|
+
if self._language != "English":
|
9921
|
+
from seleniumbase.fixtures.words import SD
|
9922
|
+
|
9923
|
+
a_t = SD.translate_assert_text(self._language)
|
9924
|
+
i_n = SD.translate_in(self._language)
|
9925
|
+
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
9926
|
+
a_t, _text, i_n, by.upper(), selector
|
9927
|
+
)
|
9928
|
+
self.__highlight_with_assert_success(
|
9929
|
+
messenger_post, selector, by
|
9930
|
+
)
|
9931
|
+
elif self.__is_cdp_swap_needed():
|
9932
|
+
self.cdp.assert_text(text, selector)
|
9933
|
+
return True
|
9934
|
+
elif not self.is_connected():
|
9935
|
+
self.connect()
|
9936
|
+
elif self.__is_shadow_selector(selector):
|
9474
9937
|
self.__assert_shadow_text_visible(text, selector, timeout)
|
9475
9938
|
return True
|
9476
|
-
|
9477
|
-
|
9478
|
-
|
9479
|
-
|
9480
|
-
|
9481
|
-
|
9939
|
+
else:
|
9940
|
+
self.wait_for_text_visible(text, selector, by=by, timeout=timeout)
|
9941
|
+
if self.demo_mode:
|
9942
|
+
a_t = "ASSERT TEXT"
|
9943
|
+
i_n = "in"
|
9944
|
+
if self._language != "English":
|
9945
|
+
from seleniumbase.fixtures.words import SD
|
9482
9946
|
|
9483
|
-
|
9484
|
-
|
9485
|
-
|
9486
|
-
|
9487
|
-
|
9488
|
-
|
9489
|
-
|
9490
|
-
|
9491
|
-
)
|
9492
|
-
self.__highlight_with_assert_success(messenger_post, selector, by)
|
9947
|
+
a_t = SD.translate_assert_text(self._language)
|
9948
|
+
i_n = SD.translate_in(self._language)
|
9949
|
+
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
9950
|
+
a_t, text, i_n, by.upper(), selector
|
9951
|
+
)
|
9952
|
+
self.__highlight_with_assert_success(
|
9953
|
+
messenger_post, selector, by
|
9954
|
+
)
|
9493
9955
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9494
9956
|
if self.get_session_storage_item("pause_recorder") == "no":
|
9495
9957
|
if by == By.XPATH:
|
@@ -9502,7 +9964,7 @@ class BaseCase(unittest.TestCase):
|
|
9502
9964
|
return True
|
9503
9965
|
|
9504
9966
|
def assert_exact_text(
|
9505
|
-
self, text, selector="
|
9967
|
+
self, text, selector="body", by="css selector", timeout=None
|
9506
9968
|
):
|
9507
9969
|
"""Similar to assert_text(), but the text must be exact,
|
9508
9970
|
rather than exist as a subset of the full text.
|
@@ -9516,6 +9978,9 @@ class BaseCase(unittest.TestCase):
|
|
9516
9978
|
timeout = self.__get_new_timeout(timeout)
|
9517
9979
|
original_selector = selector
|
9518
9980
|
selector, by = self.__recalculate_selector(selector, by)
|
9981
|
+
if self.__is_cdp_swap_needed():
|
9982
|
+
self.cdp.assert_exact_text(text, selector)
|
9983
|
+
return True
|
9519
9984
|
if self.__is_shadow_selector(selector):
|
9520
9985
|
self.__assert_exact_shadow_text_visible(text, selector, timeout)
|
9521
9986
|
return True
|
@@ -9531,11 +9996,7 @@ class BaseCase(unittest.TestCase):
|
|
9531
9996
|
a_t = SD.translate_assert_exact_text(self._language)
|
9532
9997
|
i_n = SD.translate_in(self._language)
|
9533
9998
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
9534
|
-
a_t,
|
9535
|
-
text,
|
9536
|
-
i_n,
|
9537
|
-
by.upper(),
|
9538
|
-
selector,
|
9999
|
+
a_t, text, i_n, by.upper(), selector
|
9539
10000
|
)
|
9540
10001
|
self.__highlight_with_assert_success(messenger_post, selector, by)
|
9541
10002
|
if self.recorder_mode and self.__current_url_is_recordable():
|
@@ -9550,7 +10011,7 @@ class BaseCase(unittest.TestCase):
|
|
9550
10011
|
return True
|
9551
10012
|
|
9552
10013
|
def assert_non_empty_text(
|
9553
|
-
self, selector="
|
10014
|
+
self, selector="body", by="css selector", timeout=None
|
9554
10015
|
):
|
9555
10016
|
"""Assert that the element has any non-empty text visible.
|
9556
10017
|
Raises an exception if the element has no text within the timeout.
|
@@ -9575,10 +10036,7 @@ class BaseCase(unittest.TestCase):
|
|
9575
10036
|
a_t = SD.translate_assert_non_empty_text(self._language)
|
9576
10037
|
i_n = SD.translate_in(self._language)
|
9577
10038
|
messenger_post = "<b>%s</b> %s %s: %s" % (
|
9578
|
-
a_t,
|
9579
|
-
i_n,
|
9580
|
-
by.upper(),
|
9581
|
-
selector,
|
10039
|
+
a_t, i_n, by.upper(), selector
|
9582
10040
|
)
|
9583
10041
|
self.__highlight_with_assert_success(messenger_post, selector, by)
|
9584
10042
|
if self.recorder_mode and self.__current_url_is_recordable():
|
@@ -9673,13 +10131,16 @@ class BaseCase(unittest.TestCase):
|
|
9673
10131
|
|
9674
10132
|
def assert_link_text(self, link_text, timeout=None):
|
9675
10133
|
"""Similar to wait_for_link_text_visible(), but returns nothing.
|
9676
|
-
As above,
|
10134
|
+
As above, raises an exception if nothing can be found.
|
9677
10135
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9678
10136
|
self.__check_scope()
|
9679
10137
|
if not timeout:
|
9680
10138
|
timeout = settings.SMALL_TIMEOUT
|
9681
10139
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9682
10140
|
timeout = self.__get_new_timeout(timeout)
|
10141
|
+
if self.__is_cdp_swap_needed():
|
10142
|
+
self.cdp.find_element(link_text, timeout=timeout)
|
10143
|
+
return
|
9683
10144
|
self.wait_for_link_text_visible(link_text, timeout=timeout)
|
9684
10145
|
if self.demo_mode:
|
9685
10146
|
a_t = "ASSERT LINK TEXT"
|
@@ -9722,7 +10183,7 @@ class BaseCase(unittest.TestCase):
|
|
9722
10183
|
|
9723
10184
|
def assert_partial_link_text(self, partial_link_text, timeout=None):
|
9724
10185
|
"""Similar to wait_for_partial_link_text(), but returns nothing.
|
9725
|
-
As above,
|
10186
|
+
As above, raises an exception if nothing can be found.
|
9726
10187
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9727
10188
|
self.__check_scope()
|
9728
10189
|
if not timeout:
|
@@ -9768,7 +10229,7 @@ class BaseCase(unittest.TestCase):
|
|
9768
10229
|
|
9769
10230
|
def assert_element_absent(self, selector, by="css selector", timeout=None):
|
9770
10231
|
"""Similar to wait_for_element_absent()
|
9771
|
-
As above,
|
10232
|
+
As above, raises an exception if the element stays present.
|
9772
10233
|
A hidden element counts as a present element, which fails this assert.
|
9773
10234
|
If you want to assert that elements are hidden instead of nonexistent,
|
9774
10235
|
use assert_element_not_visible() instead.
|
@@ -9779,6 +10240,9 @@ class BaseCase(unittest.TestCase):
|
|
9779
10240
|
timeout = settings.SMALL_TIMEOUT
|
9780
10241
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9781
10242
|
timeout = self.__get_new_timeout(timeout)
|
10243
|
+
if self.__is_cdp_swap_needed():
|
10244
|
+
self.cdp.assert_element_absent(selector)
|
10245
|
+
return True
|
9782
10246
|
self.wait_for_element_absent(selector, by=by, timeout=timeout)
|
9783
10247
|
return True
|
9784
10248
|
|
@@ -9797,6 +10261,9 @@ class BaseCase(unittest.TestCase):
|
|
9797
10261
|
timeout = self.__get_new_timeout(timeout)
|
9798
10262
|
original_selector = selector
|
9799
10263
|
selector, by = self.__recalculate_selector(selector, by)
|
10264
|
+
if self.__is_cdp_swap_needed():
|
10265
|
+
self.cdp.assert_element_not_visible(selector)
|
10266
|
+
return True
|
9800
10267
|
return page_actions.wait_for_element_not_visible(
|
9801
10268
|
self.driver,
|
9802
10269
|
selector,
|
@@ -9809,13 +10276,16 @@ class BaseCase(unittest.TestCase):
|
|
9809
10276
|
self, selector, by="css selector", timeout=None
|
9810
10277
|
):
|
9811
10278
|
"""Similar to wait_for_element_not_visible()
|
9812
|
-
As above,
|
10279
|
+
As above, raises an exception if the element stays visible.
|
9813
10280
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9814
10281
|
self.__check_scope()
|
9815
10282
|
if not timeout:
|
9816
10283
|
timeout = settings.SMALL_TIMEOUT
|
9817
10284
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9818
10285
|
timeout = self.__get_new_timeout(timeout)
|
10286
|
+
if self.__is_cdp_swap_needed():
|
10287
|
+
self.cdp.assert_element_not_visible(selector)
|
10288
|
+
return True
|
9819
10289
|
self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
|
9820
10290
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9821
10291
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -9828,7 +10298,7 @@ class BaseCase(unittest.TestCase):
|
|
9828
10298
|
############
|
9829
10299
|
|
9830
10300
|
def wait_for_text_not_visible(
|
9831
|
-
self, text, selector="
|
10301
|
+
self, text, selector="body", by="css selector", timeout=None
|
9832
10302
|
):
|
9833
10303
|
self.__check_scope()
|
9834
10304
|
if not timeout:
|
@@ -9841,7 +10311,7 @@ class BaseCase(unittest.TestCase):
|
|
9841
10311
|
)
|
9842
10312
|
|
9843
10313
|
def wait_for_exact_text_not_visible(
|
9844
|
-
self, text, selector="
|
10314
|
+
self, text, selector="body", by="css selector", timeout=None
|
9845
10315
|
):
|
9846
10316
|
self.__check_scope()
|
9847
10317
|
if not timeout:
|
@@ -9854,7 +10324,7 @@ class BaseCase(unittest.TestCase):
|
|
9854
10324
|
)
|
9855
10325
|
|
9856
10326
|
def assert_text_not_visible(
|
9857
|
-
self, text, selector="
|
10327
|
+
self, text, selector="body", by="css selector", timeout=None
|
9858
10328
|
):
|
9859
10329
|
"""Similar to wait_for_text_not_visible()
|
9860
10330
|
Raises an exception if the text is still visible after timeout.
|
@@ -9875,7 +10345,7 @@ class BaseCase(unittest.TestCase):
|
|
9875
10345
|
return True
|
9876
10346
|
|
9877
10347
|
def assert_exact_text_not_visible(
|
9878
|
-
self, text, selector="
|
10348
|
+
self, text, selector="body", by="css selector", timeout=None
|
9879
10349
|
):
|
9880
10350
|
"""Similar to wait_for_exact_text_not_visible()
|
9881
10351
|
Raises an exception if the exact text is still visible after timeout.
|
@@ -10125,7 +10595,7 @@ class BaseCase(unittest.TestCase):
|
|
10125
10595
|
countdown_on = True
|
10126
10596
|
countdown = 3
|
10127
10597
|
minified_exception += line + "\n"
|
10128
|
-
elif line.startswith("+"
|
10598
|
+
elif line.startswith(("+", "-")):
|
10129
10599
|
minified_exception += line + "\n"
|
10130
10600
|
elif line.startswith("?"):
|
10131
10601
|
minified_exception += line + "\n"
|
@@ -10174,8 +10644,6 @@ class BaseCase(unittest.TestCase):
|
|
10174
10644
|
shutil.copy(latest_png_path, latest_copy_path)
|
10175
10645
|
if len(self.__visual_baseline_copies) != 1:
|
10176
10646
|
return # Skip the rest when deferred visual asserts are used
|
10177
|
-
from seleniumbase.core import visual_helper
|
10178
|
-
|
10179
10647
|
the_html = visual_helper.get_sbs_html()
|
10180
10648
|
file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
|
10181
10649
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
@@ -10262,12 +10730,10 @@ class BaseCase(unittest.TestCase):
|
|
10262
10730
|
self.check_window(name="github_page", level=2)
|
10263
10731
|
self.check_window(name="wikipedia_page", level=3) """
|
10264
10732
|
self.wait_for_ready_state_complete()
|
10265
|
-
|
10733
|
+
with suppress(Exception):
|
10266
10734
|
self.wait_for_element_visible(
|
10267
10735
|
"body", timeout=settings.MINI_TIMEOUT
|
10268
10736
|
)
|
10269
|
-
except Exception:
|
10270
|
-
pass
|
10271
10737
|
if self.__needs_minimum_wait():
|
10272
10738
|
time.sleep(0.08)
|
10273
10739
|
if level == "0":
|
@@ -10293,7 +10759,6 @@ class BaseCase(unittest.TestCase):
|
|
10293
10759
|
if not name or len(name) < 1:
|
10294
10760
|
name = "default"
|
10295
10761
|
name = str(name)
|
10296
|
-
from seleniumbase.core import visual_helper
|
10297
10762
|
|
10298
10763
|
visual_helper.visual_baseline_folder_setup()
|
10299
10764
|
baseline_dir = constants.VisualBaseline.STORAGE_FOLDER
|
@@ -10510,6 +10975,12 @@ class BaseCase(unittest.TestCase):
|
|
10510
10975
|
|
10511
10976
|
############
|
10512
10977
|
|
10978
|
+
def __is_cdp_swap_needed(self):
|
10979
|
+
"""If the driver is disconnected, use a CDP method when available."""
|
10980
|
+
return shared_utils.is_cdp_swap_needed(self.driver)
|
10981
|
+
|
10982
|
+
############
|
10983
|
+
|
10513
10984
|
def __check_scope(self):
|
10514
10985
|
if hasattr(self, "browser"): # self.browser stores the type of browser
|
10515
10986
|
return # All good: setUp() already initialized variables in "self"
|
@@ -10576,14 +11047,12 @@ class BaseCase(unittest.TestCase):
|
|
10576
11047
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10577
11048
|
timeout = self.__get_new_timeout(timeout)
|
10578
11049
|
self.__deferred_assert_count += 1
|
10579
|
-
|
11050
|
+
with suppress(Exception):
|
10580
11051
|
url = self.get_current_url()
|
10581
11052
|
if url == self.__last_url_of_deferred_assert:
|
10582
11053
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10583
11054
|
else:
|
10584
11055
|
self.__last_url_of_deferred_assert = url
|
10585
|
-
except Exception:
|
10586
|
-
pass
|
10587
11056
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10588
11057
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10589
11058
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10613,14 +11082,12 @@ class BaseCase(unittest.TestCase):
|
|
10613
11082
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10614
11083
|
timeout = self.__get_new_timeout(timeout)
|
10615
11084
|
self.__deferred_assert_count += 1
|
10616
|
-
|
11085
|
+
with suppress(Exception):
|
10617
11086
|
url = self.get_current_url()
|
10618
11087
|
if url == self.__last_url_of_deferred_assert:
|
10619
11088
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10620
11089
|
else:
|
10621
11090
|
self.__last_url_of_deferred_assert = url
|
10622
|
-
except Exception:
|
10623
|
-
pass
|
10624
11091
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10625
11092
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10626
11093
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10635,7 +11102,7 @@ class BaseCase(unittest.TestCase):
|
|
10635
11102
|
return False
|
10636
11103
|
|
10637
11104
|
def deferred_assert_text(
|
10638
|
-
self, text, selector="
|
11105
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10639
11106
|
):
|
10640
11107
|
"""A non-terminating assertion for text from an element on a page.
|
10641
11108
|
Failures will be saved until the process_deferred_asserts()
|
@@ -10650,14 +11117,12 @@ class BaseCase(unittest.TestCase):
|
|
10650
11117
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10651
11118
|
timeout = self.__get_new_timeout(timeout)
|
10652
11119
|
self.__deferred_assert_count += 1
|
10653
|
-
|
11120
|
+
with suppress(Exception):
|
10654
11121
|
url = self.get_current_url()
|
10655
11122
|
if url == self.__last_url_of_deferred_assert:
|
10656
11123
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10657
11124
|
else:
|
10658
11125
|
self.__last_url_of_deferred_assert = url
|
10659
|
-
except Exception:
|
10660
|
-
pass
|
10661
11126
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10662
11127
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10663
11128
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10673,7 +11138,7 @@ class BaseCase(unittest.TestCase):
|
|
10673
11138
|
return False
|
10674
11139
|
|
10675
11140
|
def deferred_assert_exact_text(
|
10676
|
-
self, text, selector="
|
11141
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10677
11142
|
):
|
10678
11143
|
"""A non-terminating assertion for exact text from an element.
|
10679
11144
|
Failures will be saved until the process_deferred_asserts()
|
@@ -10688,14 +11153,12 @@ class BaseCase(unittest.TestCase):
|
|
10688
11153
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10689
11154
|
timeout = self.__get_new_timeout(timeout)
|
10690
11155
|
self.__deferred_assert_count += 1
|
10691
|
-
|
11156
|
+
with suppress(Exception):
|
10692
11157
|
url = self.get_current_url()
|
10693
11158
|
if url == self.__last_url_of_deferred_assert:
|
10694
11159
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10695
11160
|
else:
|
10696
11161
|
self.__last_url_of_deferred_assert = url
|
10697
|
-
except Exception:
|
10698
|
-
pass
|
10699
11162
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10700
11163
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10701
11164
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10714,7 +11177,7 @@ class BaseCase(unittest.TestCase):
|
|
10714
11177
|
|
10715
11178
|
def deferred_assert_non_empty_text(
|
10716
11179
|
self,
|
10717
|
-
selector="
|
11180
|
+
selector="body",
|
10718
11181
|
by="css selector",
|
10719
11182
|
timeout=None,
|
10720
11183
|
fs=False,
|
@@ -10732,14 +11195,12 @@ class BaseCase(unittest.TestCase):
|
|
10732
11195
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10733
11196
|
timeout = self.__get_new_timeout(timeout)
|
10734
11197
|
self.__deferred_assert_count += 1
|
10735
|
-
|
11198
|
+
with suppress(Exception):
|
10736
11199
|
url = self.get_current_url()
|
10737
11200
|
if url == self.__last_url_of_deferred_assert:
|
10738
11201
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10739
11202
|
else:
|
10740
11203
|
self.__last_url_of_deferred_assert = url
|
10741
|
-
except Exception:
|
10742
|
-
pass
|
10743
11204
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10744
11205
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10745
11206
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10836,7 +11297,7 @@ class BaseCase(unittest.TestCase):
|
|
10836
11297
|
)
|
10837
11298
|
|
10838
11299
|
def delayed_assert_text(
|
10839
|
-
self, text, selector="
|
11300
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10840
11301
|
):
|
10841
11302
|
"""Same as self.deferred_assert_text()"""
|
10842
11303
|
return self.deferred_assert_text(
|
@@ -10844,7 +11305,7 @@ class BaseCase(unittest.TestCase):
|
|
10844
11305
|
)
|
10845
11306
|
|
10846
11307
|
def delayed_assert_exact_text(
|
10847
|
-
self, text, selector="
|
11308
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10848
11309
|
):
|
10849
11310
|
"""Same as self.deferred_assert_exact_text()"""
|
10850
11311
|
return self.deferred_assert_exact_text(
|
@@ -10853,7 +11314,7 @@ class BaseCase(unittest.TestCase):
|
|
10853
11314
|
|
10854
11315
|
def delayed_assert_non_empty_text(
|
10855
11316
|
self,
|
10856
|
-
selector="
|
11317
|
+
selector="body",
|
10857
11318
|
by="css selector",
|
10858
11319
|
timeout=None,
|
10859
11320
|
fs=False,
|
@@ -11175,10 +11636,8 @@ class BaseCase(unittest.TestCase):
|
|
11175
11636
|
if saved_presentations_folder.endswith("/"):
|
11176
11637
|
saved_presentations_folder = saved_presentations_folder[:-1]
|
11177
11638
|
if not os.path.exists(saved_presentations_folder):
|
11178
|
-
|
11639
|
+
with suppress(Exception):
|
11179
11640
|
os.makedirs(saved_presentations_folder)
|
11180
|
-
except Exception:
|
11181
|
-
pass
|
11182
11641
|
file_path = os.path.join(saved_presentations_folder, filename)
|
11183
11642
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
11184
11643
|
out_file.writelines(the_html)
|
@@ -11232,7 +11691,7 @@ class BaseCase(unittest.TestCase):
|
|
11232
11691
|
self._presentation_slides[name].pop()
|
11233
11692
|
self.open_html_file(file_path)
|
11234
11693
|
presentation_folder = constants.Presentations.SAVED_FOLDER
|
11235
|
-
|
11694
|
+
with suppress(Exception):
|
11236
11695
|
while (
|
11237
11696
|
len(self.driver.window_handles) > 0
|
11238
11697
|
and presentation_folder in self.get_current_url()
|
@@ -11243,8 +11702,6 @@ class BaseCase(unittest.TestCase):
|
|
11243
11702
|
):
|
11244
11703
|
break
|
11245
11704
|
time.sleep(0.05)
|
11246
|
-
except Exception:
|
11247
|
-
pass
|
11248
11705
|
|
11249
11706
|
############
|
11250
11707
|
|
@@ -11874,10 +12331,8 @@ class BaseCase(unittest.TestCase):
|
|
11874
12331
|
if saved_charts_folder.endswith("/"):
|
11875
12332
|
saved_charts_folder = saved_charts_folder[:-1]
|
11876
12333
|
if not os.path.exists(saved_charts_folder):
|
11877
|
-
|
12334
|
+
with suppress(Exception):
|
11878
12335
|
os.makedirs(saved_charts_folder)
|
11879
|
-
except Exception:
|
11880
|
-
pass
|
11881
12336
|
file_path = os.path.join(saved_charts_folder, filename)
|
11882
12337
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
11883
12338
|
out_file.writelines(the_html)
|
@@ -11917,17 +12372,15 @@ class BaseCase(unittest.TestCase):
|
|
11917
12372
|
self.open_html_file(file_path)
|
11918
12373
|
chart_folder = constants.Charts.SAVED_FOLDER
|
11919
12374
|
if interval == 0:
|
11920
|
-
|
12375
|
+
with suppress(Exception):
|
11921
12376
|
print("\n*** Close the browser window to continue ***")
|
11922
12377
|
# Will also continue if manually navigating to a new page
|
11923
12378
|
while len(self.driver.window_handles) > 0 and (
|
11924
12379
|
chart_folder in self.get_current_url()
|
11925
12380
|
):
|
11926
12381
|
time.sleep(0.05)
|
11927
|
-
except Exception:
|
11928
|
-
pass
|
11929
12382
|
else:
|
11930
|
-
|
12383
|
+
with suppress(Exception):
|
11931
12384
|
start_ms = time.time() * 1000.0
|
11932
12385
|
stop_ms = start_ms + (interval * 1000.0)
|
11933
12386
|
for x in range(int(interval * 10)):
|
@@ -11939,8 +12392,6 @@ class BaseCase(unittest.TestCase):
|
|
11939
12392
|
if chart_folder not in self.get_current_url():
|
11940
12393
|
break
|
11941
12394
|
time.sleep(0.1)
|
11942
|
-
except Exception:
|
11943
|
-
pass
|
11944
12395
|
|
11945
12396
|
def extract_chart(self, chart_name=None):
|
11946
12397
|
"""Extracts the HTML from a SeleniumBase-generated chart.
|
@@ -12752,10 +13203,8 @@ class BaseCase(unittest.TestCase):
|
|
12752
13203
|
)
|
12753
13204
|
time.sleep(0.02)
|
12754
13205
|
jf = "document.querySelector('.jconfirm-box').focus();"
|
12755
|
-
|
13206
|
+
with suppress(Exception):
|
12756
13207
|
self.execute_script(jf)
|
12757
|
-
except Exception:
|
12758
|
-
pass
|
12759
13208
|
waiting_for_response = True
|
12760
13209
|
while waiting_for_response:
|
12761
13210
|
time.sleep(0.05)
|
@@ -12827,10 +13276,8 @@ class BaseCase(unittest.TestCase):
|
|
12827
13276
|
)
|
12828
13277
|
time.sleep(0.02)
|
12829
13278
|
jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
|
12830
|
-
|
13279
|
+
with suppress(Exception):
|
12831
13280
|
self.execute_script(jf)
|
12832
|
-
except Exception:
|
12833
|
-
pass
|
12834
13281
|
waiting_for_response = True
|
12835
13282
|
while waiting_for_response:
|
12836
13283
|
time.sleep(0.05)
|
@@ -12891,10 +13338,8 @@ class BaseCase(unittest.TestCase):
|
|
12891
13338
|
)
|
12892
13339
|
time.sleep(0.02)
|
12893
13340
|
jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
|
12894
|
-
|
13341
|
+
with suppress(Exception):
|
12895
13342
|
self.execute_script(jf)
|
12896
|
-
except Exception:
|
12897
|
-
pass
|
12898
13343
|
waiting_for_response = True
|
12899
13344
|
while waiting_for_response:
|
12900
13345
|
time.sleep(0.05)
|
@@ -12969,12 +13414,10 @@ class BaseCase(unittest.TestCase):
|
|
12969
13414
|
if not page_actions.is_element_clickable(
|
12970
13415
|
self.driver, selector, by
|
12971
13416
|
):
|
12972
|
-
|
13417
|
+
with suppress(Exception):
|
12973
13418
|
self.wait_for_element_clickable(
|
12974
13419
|
selector, by, timeout=1.8
|
12975
13420
|
)
|
12976
|
-
except Exception:
|
12977
|
-
pass
|
12978
13421
|
# If the regular mouse-simulated click fails, do a basic JS click
|
12979
13422
|
script = (
|
12980
13423
|
"""document.querySelector('%s').click();"""
|
@@ -13050,8 +13493,6 @@ class BaseCase(unittest.TestCase):
|
|
13050
13493
|
timeout=None,
|
13051
13494
|
center=None,
|
13052
13495
|
):
|
13053
|
-
from selenium.webdriver.common.action_chains import ActionChains
|
13054
|
-
|
13055
13496
|
self.wait_for_ready_state_complete()
|
13056
13497
|
if self.__needs_minimum_wait():
|
13057
13498
|
time.sleep(0.14)
|
@@ -13210,8 +13651,7 @@ class BaseCase(unittest.TestCase):
|
|
13210
13651
|
|
13211
13652
|
def __get_major_browser_version(self):
|
13212
13653
|
version = self.driver.__dict__["caps"]["browserVersion"]
|
13213
|
-
|
13214
|
-
return major_browser_version
|
13654
|
+
return version.split(".")[0]
|
13215
13655
|
|
13216
13656
|
def __get_href_from_link_text(self, link_text, hard_fail=True):
|
13217
13657
|
href = self.get_link_attribute(link_text, "href", hard_fail)
|
@@ -13249,7 +13689,7 @@ class BaseCase(unittest.TestCase):
|
|
13249
13689
|
for dropdown in matching_dropdowns:
|
13250
13690
|
# The same class names might be used for multiple dropdowns
|
13251
13691
|
if dropdown.is_displayed():
|
13252
|
-
|
13692
|
+
with suppress(Exception):
|
13253
13693
|
try:
|
13254
13694
|
page_actions.hover_element(
|
13255
13695
|
self.driver,
|
@@ -13270,9 +13710,6 @@ class BaseCase(unittest.TestCase):
|
|
13270
13710
|
timeout=0.12,
|
13271
13711
|
)
|
13272
13712
|
return True
|
13273
|
-
except Exception:
|
13274
|
-
pass
|
13275
|
-
|
13276
13713
|
return False
|
13277
13714
|
|
13278
13715
|
def __get_href_from_partial_link_text(self, link_text, hard_fail=True):
|
@@ -13313,7 +13750,7 @@ class BaseCase(unittest.TestCase):
|
|
13313
13750
|
for dropdown in matching_dropdowns:
|
13314
13751
|
# The same class names might be used for multiple dropdowns
|
13315
13752
|
if dropdown.is_displayed():
|
13316
|
-
|
13753
|
+
with suppress(Exception):
|
13317
13754
|
try:
|
13318
13755
|
page_actions.hover_element(
|
13319
13756
|
self.driver, dropdown
|
@@ -13335,8 +13772,6 @@ class BaseCase(unittest.TestCase):
|
|
13335
13772
|
timeout=0.12,
|
13336
13773
|
)
|
13337
13774
|
return True
|
13338
|
-
except Exception:
|
13339
|
-
pass
|
13340
13775
|
return False
|
13341
13776
|
|
13342
13777
|
def __recalculate_selector(self, selector, by, xp_ok=True):
|
@@ -13360,7 +13795,8 @@ class BaseCase(unittest.TestCase):
|
|
13360
13795
|
if self.get_current_url() == "about:blank":
|
13361
13796
|
self.switch_to_window(current_window)
|
13362
13797
|
except Exception:
|
13363
|
-
|
13798
|
+
with suppress(Exception):
|
13799
|
+
self.switch_to_window(current_window)
|
13364
13800
|
|
13365
13801
|
def __needs_minimum_wait(self):
|
13366
13802
|
if (
|
@@ -13396,6 +13832,7 @@ class BaseCase(unittest.TestCase):
|
|
13396
13832
|
self.slow_scroll_to(selector, by=by)
|
13397
13833
|
|
13398
13834
|
def __demo_mode_highlight_if_active(self, selector, by):
|
13835
|
+
self.__skip_if_esc()
|
13399
13836
|
if self.demo_mode:
|
13400
13837
|
# Includes self.slow_scroll_to(selector, by=by) by default
|
13401
13838
|
self.__highlight(selector, by=by)
|
@@ -13443,7 +13880,8 @@ class BaseCase(unittest.TestCase):
|
|
13443
13880
|
js_utils.scroll_to_element(self.driver, element)
|
13444
13881
|
|
13445
13882
|
def __highlight_with_js(self, selector, loops, o_bs):
|
13446
|
-
self.
|
13883
|
+
if not self.__is_cdp_swap_needed():
|
13884
|
+
self.wait_for_ready_state_complete()
|
13447
13885
|
js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
|
13448
13886
|
|
13449
13887
|
def __highlight_element_with_js(self, element, loops, o_bs):
|
@@ -13558,23 +13996,112 @@ class BaseCase(unittest.TestCase):
|
|
13558
13996
|
pass # JQuery probably couldn't load. Skip highlighting.
|
13559
13997
|
time.sleep(0.065)
|
13560
13998
|
|
13999
|
+
def __activate_standard_virtual_display(self):
|
14000
|
+
from sbvirtualdisplay import Display
|
14001
|
+
width = settings.HEADLESS_START_WIDTH
|
14002
|
+
height = settings.HEADLESS_START_HEIGHT
|
14003
|
+
with suppress(Exception):
|
14004
|
+
self._xvfb_display = Display(
|
14005
|
+
visible=0, size=(width, height)
|
14006
|
+
)
|
14007
|
+
self._xvfb_display.start()
|
14008
|
+
self.headless_active = True
|
14009
|
+
if not self.undetectable:
|
14010
|
+
sb_config._virtual_display = self._xvfb_display
|
14011
|
+
sb_config.headless_active = True
|
14012
|
+
|
14013
|
+
def __activate_virtual_display(self):
|
14014
|
+
if self.undetectable and not (self.headless or self.headless2):
|
14015
|
+
from sbvirtualdisplay import Display
|
14016
|
+
import Xlib.display
|
14017
|
+
try:
|
14018
|
+
if not self._xvfb_width:
|
14019
|
+
self._xvfb_width = 1366
|
14020
|
+
if not self._xvfb_height:
|
14021
|
+
self._xvfb_height = 768
|
14022
|
+
self._xvfb_display = Display(
|
14023
|
+
visible=True,
|
14024
|
+
size=(self._xvfb_width, self._xvfb_height),
|
14025
|
+
backend="xvfb",
|
14026
|
+
use_xauth=True,
|
14027
|
+
)
|
14028
|
+
self._xvfb_display.start()
|
14029
|
+
if "DISPLAY" not in os.environ.keys():
|
14030
|
+
print(
|
14031
|
+
"\nX11 display failed! Will use regular xvfb!"
|
14032
|
+
)
|
14033
|
+
self.__activate_standard_virtual_display()
|
14034
|
+
else:
|
14035
|
+
self.headless_active = True
|
14036
|
+
except Exception as e:
|
14037
|
+
if hasattr(e, "msg"):
|
14038
|
+
print("\n" + str(e.msg))
|
14039
|
+
else:
|
14040
|
+
print(e)
|
14041
|
+
print("\nX11 display failed! Will use regular xvfb!")
|
14042
|
+
self.__activate_standard_virtual_display()
|
14043
|
+
return
|
14044
|
+
pyautogui_is_installed = False
|
14045
|
+
try:
|
14046
|
+
import pyautogui
|
14047
|
+
with suppress(Exception):
|
14048
|
+
use_pyautogui_ver = constants.PyAutoGUI.VER
|
14049
|
+
if pyautogui.__version__ != use_pyautogui_ver:
|
14050
|
+
del pyautogui # To get newer ver
|
14051
|
+
shared_utils.pip_install(
|
14052
|
+
"pyautogui", version=use_pyautogui_ver
|
14053
|
+
)
|
14054
|
+
import pyautogui
|
14055
|
+
pyautogui_is_installed = True
|
14056
|
+
except Exception:
|
14057
|
+
message = (
|
14058
|
+
"PyAutoGUI is required for UC Mode on Linux! "
|
14059
|
+
"Installing now..."
|
14060
|
+
)
|
14061
|
+
print("\n" + message)
|
14062
|
+
shared_utils.pip_install(
|
14063
|
+
"pyautogui", version=constants.PyAutoGUI.VER
|
14064
|
+
)
|
14065
|
+
import pyautogui
|
14066
|
+
pyautogui_is_installed = True
|
14067
|
+
if (
|
14068
|
+
pyautogui_is_installed
|
14069
|
+
and hasattr(pyautogui, "_pyautogui_x11")
|
14070
|
+
):
|
14071
|
+
try:
|
14072
|
+
pyautogui._pyautogui_x11._display = (
|
14073
|
+
Xlib.display.Display(os.environ['DISPLAY'])
|
14074
|
+
)
|
14075
|
+
sb_config._pyautogui_x11_display = (
|
14076
|
+
pyautogui._pyautogui_x11._display
|
14077
|
+
)
|
14078
|
+
except Exception as e:
|
14079
|
+
if hasattr(e, "msg"):
|
14080
|
+
print("\n" + str(e.msg))
|
14081
|
+
else:
|
14082
|
+
print(e)
|
14083
|
+
else:
|
14084
|
+
self.__activate_standard_virtual_display()
|
14085
|
+
|
13561
14086
|
def __activate_virtual_display_as_needed(self):
|
13562
|
-
"""
|
14087
|
+
"""This is only needed on Linux.
|
13563
14088
|
The "--xvfb" arg is still useful, as it prevents headless mode,
|
13564
14089
|
which is the default mode on Linux unless using another arg."""
|
13565
14090
|
if "linux" in sys.platform and (not self.headed or self.xvfb):
|
13566
|
-
|
13567
|
-
|
14091
|
+
pip_find_lock = fasteners.InterProcessLock(
|
14092
|
+
constants.PipInstall.FINDLOCK
|
14093
|
+
)
|
13568
14094
|
try:
|
13569
|
-
|
13570
|
-
|
13571
|
-
self._xvfb_display = Display(visible=0, size=(width, height))
|
13572
|
-
self._xvfb_display.start()
|
13573
|
-
sb_config._virtual_display = self._xvfb_display
|
13574
|
-
self.headless_active = True
|
13575
|
-
sb_config.headless_active = True
|
14095
|
+
with pip_find_lock:
|
14096
|
+
pass
|
13576
14097
|
except Exception:
|
13577
|
-
|
14098
|
+
# Since missing permissions, skip the locks
|
14099
|
+
self.__activate_virtual_display()
|
14100
|
+
return
|
14101
|
+
with pip_find_lock: # Prevent issues with multiple processes
|
14102
|
+
with suppress(Exception):
|
14103
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
14104
|
+
self.__activate_virtual_display()
|
13578
14105
|
|
13579
14106
|
def __ad_block_as_needed(self):
|
13580
14107
|
"""This is an internal method for handling ad-blocking.
|
@@ -13796,12 +14323,10 @@ class BaseCase(unittest.TestCase):
|
|
13796
14323
|
selector, timeout=timeout, must_be_visible=True
|
13797
14324
|
)
|
13798
14325
|
if clear_first:
|
13799
|
-
|
14326
|
+
with suppress(Exception):
|
13800
14327
|
element.clear()
|
13801
14328
|
backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
|
13802
14329
|
element.send_keys(backspaces)
|
13803
|
-
except Exception:
|
13804
|
-
pass
|
13805
14330
|
text = self.__get_type_checked_text(text)
|
13806
14331
|
if not text.endswith("\n"):
|
13807
14332
|
element.send_keys(text)
|
@@ -13817,12 +14342,10 @@ class BaseCase(unittest.TestCase):
|
|
13817
14342
|
element = self.__get_shadow_element(
|
13818
14343
|
selector, timeout=timeout, must_be_visible=True
|
13819
14344
|
)
|
13820
|
-
|
14345
|
+
with suppress(Exception):
|
13821
14346
|
element.clear()
|
13822
14347
|
backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
|
13823
14348
|
element.send_keys(backspaces)
|
13824
|
-
except Exception:
|
13825
|
-
pass
|
13826
14349
|
|
13827
14350
|
def __get_shadow_text(self, selector, timeout):
|
13828
14351
|
element = self.__get_shadow_element(
|
@@ -13942,19 +14465,13 @@ class BaseCase(unittest.TestCase):
|
|
13942
14465
|
a_t = SD.translate_assert_text(self._language)
|
13943
14466
|
i_n = SD.translate_in(self._language)
|
13944
14467
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
13945
|
-
a_t,
|
13946
|
-
text,
|
13947
|
-
i_n,
|
13948
|
-
by.upper(),
|
13949
|
-
selector,
|
14468
|
+
a_t, text, i_n, by.upper(), selector
|
13950
14469
|
)
|
13951
|
-
|
14470
|
+
with suppress(Exception):
|
13952
14471
|
js_utils.activate_jquery(self.driver)
|
13953
14472
|
js_utils.post_messenger_success_message(
|
13954
14473
|
self.driver, messenger_post, self.message_duration
|
13955
14474
|
)
|
13956
|
-
except Exception:
|
13957
|
-
pass
|
13958
14475
|
|
13959
14476
|
def __assert_exact_shadow_text_visible(self, text, selector, timeout):
|
13960
14477
|
self.__wait_for_exact_shadow_text_visible(text, selector, timeout)
|
@@ -13968,19 +14485,13 @@ class BaseCase(unittest.TestCase):
|
|
13968
14485
|
a_t = SD.translate_assert_exact_text(self._language)
|
13969
14486
|
i_n = SD.translate_in(self._language)
|
13970
14487
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
13971
|
-
a_t,
|
13972
|
-
text,
|
13973
|
-
i_n,
|
13974
|
-
by.upper(),
|
13975
|
-
selector,
|
14488
|
+
a_t, text, i_n, by.upper(), selector
|
13976
14489
|
)
|
13977
|
-
|
14490
|
+
with suppress(Exception):
|
13978
14491
|
js_utils.activate_jquery(self.driver)
|
13979
14492
|
js_utils.post_messenger_success_message(
|
13980
14493
|
self.driver, messenger_post, self.message_duration
|
13981
14494
|
)
|
13982
|
-
except Exception:
|
13983
|
-
pass
|
13984
14495
|
|
13985
14496
|
def __assert_non_empty_shadow_text_visible(self, selector, timeout, strip):
|
13986
14497
|
self.__wait_for_non_empty_shadow_text_visible(selector, timeout, strip)
|
@@ -13994,18 +14505,13 @@ class BaseCase(unittest.TestCase):
|
|
13994
14505
|
a_t = SD.translate_assert_non_empty_text(self._language)
|
13995
14506
|
i_n = SD.translate_in(self._language)
|
13996
14507
|
messenger_post = "<b>%s</b> %s %s: %s" % (
|
13997
|
-
a_t,
|
13998
|
-
i_n,
|
13999
|
-
by.upper(),
|
14000
|
-
selector,
|
14508
|
+
a_t, i_n, by.upper(), selector
|
14001
14509
|
)
|
14002
|
-
|
14510
|
+
with suppress(Exception):
|
14003
14511
|
js_utils.activate_jquery(self.driver)
|
14004
14512
|
js_utils.post_messenger_success_message(
|
14005
14513
|
self.driver, messenger_post, self.message_duration
|
14006
14514
|
)
|
14007
|
-
except Exception:
|
14008
|
-
pass
|
14009
14515
|
|
14010
14516
|
def __is_shadow_element_present(self, selector):
|
14011
14517
|
try:
|
@@ -14133,7 +14639,7 @@ class BaseCase(unittest.TestCase):
|
|
14133
14639
|
message = (
|
14134
14640
|
"Expected value {%s} for attribute {%s} of element "
|
14135
14641
|
"{%s} was not present after %s second%s! "
|
14136
|
-
"(
|
14642
|
+
"(Actual value was {%s})"
|
14137
14643
|
% (
|
14138
14644
|
value,
|
14139
14645
|
attribute,
|
@@ -14157,13 +14663,11 @@ class BaseCase(unittest.TestCase):
|
|
14157
14663
|
|
14158
14664
|
a_t = SD.translate_assert(self._language)
|
14159
14665
|
messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
|
14160
|
-
|
14666
|
+
with suppress(Exception):
|
14161
14667
|
js_utils.activate_jquery(self.driver)
|
14162
14668
|
js_utils.post_messenger_success_message(
|
14163
14669
|
self.driver, messenger_post, self.message_duration
|
14164
14670
|
)
|
14165
|
-
except Exception:
|
14166
|
-
pass
|
14167
14671
|
|
14168
14672
|
def __assert_shadow_element_visible(self, selector):
|
14169
14673
|
element = self.__get_shadow_element(selector)
|
@@ -14178,13 +14682,11 @@ class BaseCase(unittest.TestCase):
|
|
14178
14682
|
|
14179
14683
|
a_t = SD.translate_assert(self._language)
|
14180
14684
|
messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
|
14181
|
-
|
14685
|
+
with suppress(Exception):
|
14182
14686
|
js_utils.activate_jquery(self.driver)
|
14183
14687
|
js_utils.post_messenger_success_message(
|
14184
14688
|
self.driver, messenger_post, self.message_duration
|
14185
14689
|
)
|
14186
|
-
except Exception:
|
14187
|
-
pass
|
14188
14690
|
|
14189
14691
|
############
|
14190
14692
|
|
@@ -14259,10 +14761,15 @@ class BaseCase(unittest.TestCase):
|
|
14259
14761
|
self.env = self.environment # Add a shortened version
|
14260
14762
|
self.with_selenium = sb_config.with_selenium # Should be True
|
14261
14763
|
self.headless = sb_config.headless
|
14764
|
+
self.headless1 = sb_config.headless1
|
14765
|
+
if self.headless1:
|
14766
|
+
self.headless = True
|
14767
|
+
self.headless2 = sb_config.headless2
|
14262
14768
|
self.headless_active = False
|
14263
14769
|
sb_config.headless_active = False
|
14264
14770
|
self.headed = sb_config.headed
|
14265
14771
|
self.xvfb = sb_config.xvfb
|
14772
|
+
self.xvfb_metrics = sb_config.xvfb_metrics
|
14266
14773
|
self.locale_code = sb_config.locale_code
|
14267
14774
|
self.interval = sb_config.interval
|
14268
14775
|
self.start_page = sb_config.start_page
|
@@ -14297,6 +14804,7 @@ class BaseCase(unittest.TestCase):
|
|
14297
14804
|
self.firefox_arg = sb_config.firefox_arg
|
14298
14805
|
self.firefox_pref = sb_config.firefox_pref
|
14299
14806
|
self.verify_delay = sb_config.verify_delay
|
14807
|
+
self.esc_end = sb_config.esc_end
|
14300
14808
|
self.recorder_mode = sb_config.recorder_mode
|
14301
14809
|
self.recorder_ext = sb_config.recorder_mode
|
14302
14810
|
self.rec_print = sb_config.rec_print
|
@@ -14311,6 +14819,7 @@ class BaseCase(unittest.TestCase):
|
|
14311
14819
|
elif self.record_sleep and not self.recorder_mode:
|
14312
14820
|
self.recorder_mode = True
|
14313
14821
|
self.recorder_ext = True
|
14822
|
+
self.disable_cookies = sb_config.disable_cookies
|
14314
14823
|
self.disable_js = sb_config.disable_js
|
14315
14824
|
self.disable_csp = sb_config.disable_csp
|
14316
14825
|
self.disable_ws = sb_config.disable_ws
|
@@ -14325,7 +14834,6 @@ class BaseCase(unittest.TestCase):
|
|
14325
14834
|
self.log_cdp_events = sb_config.log_cdp_events
|
14326
14835
|
self.no_sandbox = sb_config.no_sandbox
|
14327
14836
|
self.disable_gpu = sb_config.disable_gpu
|
14328
|
-
self.headless2 = sb_config.headless2
|
14329
14837
|
self.incognito = sb_config.incognito
|
14330
14838
|
self.guest_mode = sb_config.guest_mode
|
14331
14839
|
self.dark_mode = sb_config.dark_mode
|
@@ -14353,31 +14861,8 @@ class BaseCase(unittest.TestCase):
|
|
14353
14861
|
self.use_wire = sb_config.use_wire
|
14354
14862
|
self.external_pdf = sb_config.external_pdf
|
14355
14863
|
self._final_debug = sb_config.final_debug
|
14864
|
+
self.window_position = sb_config.window_position
|
14356
14865
|
self.window_size = sb_config.window_size
|
14357
|
-
window_size = self.window_size
|
14358
|
-
if window_size:
|
14359
|
-
if window_size.count(",") != 1:
|
14360
|
-
message = (
|
14361
|
-
'\n\n window_size expects a "width,height" string!'
|
14362
|
-
'\n (Your input was: "%s")\n' % window_size
|
14363
|
-
)
|
14364
|
-
raise Exception(message)
|
14365
|
-
window_size = window_size.replace(" ", "")
|
14366
|
-
width = None
|
14367
|
-
height = None
|
14368
|
-
try:
|
14369
|
-
width = int(window_size.split(",")[0])
|
14370
|
-
height = int(window_size.split(",")[1])
|
14371
|
-
except Exception:
|
14372
|
-
message = (
|
14373
|
-
'\n\n Expecting integer values for "width,height"!'
|
14374
|
-
'\n (window_size input was: "%s")\n' % window_size
|
14375
|
-
)
|
14376
|
-
raise Exception(message)
|
14377
|
-
settings.CHROME_START_WIDTH = width
|
14378
|
-
settings.CHROME_START_HEIGHT = height
|
14379
|
-
settings.HEADLESS_START_WIDTH = width
|
14380
|
-
settings.HEADLESS_START_HEIGHT = height
|
14381
14866
|
self.maximize_option = sb_config.maximize_option
|
14382
14867
|
self.save_screenshot_after_test = sb_config.save_screenshot
|
14383
14868
|
self.no_screenshot_after_test = sb_config.no_screenshot
|
@@ -14435,15 +14920,13 @@ class BaseCase(unittest.TestCase):
|
|
14435
14920
|
self.__skip_reason = None
|
14436
14921
|
self.testcase_manager.insert_testcase_data(data_payload)
|
14437
14922
|
self.case_start_time = int(time.time() * 1000.0)
|
14438
|
-
self.__activate_virtual_display_as_needed()
|
14439
14923
|
elif hasattr(self, "is_behave") and self.is_behave:
|
14440
14924
|
self.__initialize_variables()
|
14441
|
-
self.__activate_virtual_display_as_needed()
|
14442
14925
|
elif hasattr(self, "is_nosetest") and self.is_nosetest:
|
14443
14926
|
pass # Setup performed in plugins for pynose
|
14444
14927
|
else:
|
14445
|
-
# Pure Python run. Eg. SB()
|
14446
|
-
|
14928
|
+
# Pure Python run. (Eg. SB() and Driver() Managers)
|
14929
|
+
pass # Variables initialized in respective plugins
|
14447
14930
|
|
14448
14931
|
# Verify SeleniumBase is installed successfully, and used correctly
|
14449
14932
|
if not hasattr(self, "browser"):
|
@@ -14528,8 +15011,8 @@ class BaseCase(unittest.TestCase):
|
|
14528
15011
|
metrics_list = metrics_string.split(",")
|
14529
15012
|
exception_string = (
|
14530
15013
|
"Invalid input for Mobile Emulator device metrics!\n"
|
14531
|
-
"Expecting a comma-separated string with
|
14532
|
-
"
|
15014
|
+
"Expecting a comma-separated string with integer values\n"
|
15015
|
+
"for Width/Height, and an int or float for Pixel-Ratio.\n"
|
14533
15016
|
'Example: --metrics="411,731,3" '
|
14534
15017
|
)
|
14535
15018
|
if len(metrics_list) != 3:
|
@@ -14537,13 +15020,91 @@ class BaseCase(unittest.TestCase):
|
|
14537
15020
|
try:
|
14538
15021
|
self.__device_width = int(metrics_list[0])
|
14539
15022
|
self.__device_height = int(metrics_list[1])
|
14540
|
-
self.__device_pixel_ratio =
|
15023
|
+
self.__device_pixel_ratio = float(metrics_list[2])
|
14541
15024
|
self.mobile_emulator = True
|
14542
15025
|
except Exception:
|
14543
15026
|
raise Exception(exception_string)
|
15027
|
+
|
15028
|
+
window_position = self.window_position
|
15029
|
+
if window_position:
|
15030
|
+
if window_position.count(",") != 1:
|
15031
|
+
message = (
|
15032
|
+
'\n\n window_position expects an "x,y" string!'
|
15033
|
+
'\n (Your input was: "%s")\n' % window_position
|
15034
|
+
)
|
15035
|
+
raise Exception(message)
|
15036
|
+
window_position = window_position.replace(" ", "")
|
15037
|
+
win_x = None
|
15038
|
+
win_y = None
|
15039
|
+
try:
|
15040
|
+
win_x = int(window_position.split(",")[0])
|
15041
|
+
win_y = int(window_position.split(",")[1])
|
15042
|
+
except Exception:
|
15043
|
+
message = (
|
15044
|
+
'\n\n Expecting integer values for "x,y"!'
|
15045
|
+
'\n (window_position input was: "%s")\n'
|
15046
|
+
% window_position
|
15047
|
+
)
|
15048
|
+
raise Exception(message)
|
15049
|
+
settings.WINDOW_START_X = win_x
|
15050
|
+
settings.WINDOW_START_Y = win_y
|
15051
|
+
|
15052
|
+
window_size = self.window_size
|
15053
|
+
if window_size:
|
15054
|
+
if window_size.count(",") != 1:
|
15055
|
+
message = (
|
15056
|
+
'\n\n window_size expects a "width,height" string!'
|
15057
|
+
'\n (Your input was: "%s")\n' % window_size
|
15058
|
+
)
|
15059
|
+
raise Exception(message)
|
15060
|
+
window_size = window_size.replace(" ", "")
|
15061
|
+
width = None
|
15062
|
+
height = None
|
15063
|
+
try:
|
15064
|
+
width = int(window_size.split(",")[0])
|
15065
|
+
height = int(window_size.split(",")[1])
|
15066
|
+
except Exception:
|
15067
|
+
message = (
|
15068
|
+
'\n\n Expecting integer values for "width,height"!'
|
15069
|
+
'\n (window_size input was: "%s")\n' % window_size
|
15070
|
+
)
|
15071
|
+
raise Exception(message)
|
15072
|
+
settings.CHROME_START_WIDTH = width
|
15073
|
+
settings.CHROME_START_HEIGHT = height
|
15074
|
+
settings.HEADLESS_START_WIDTH = width
|
15075
|
+
settings.HEADLESS_START_HEIGHT = height
|
15076
|
+
|
15077
|
+
if self.xvfb_metrics:
|
15078
|
+
metrics_string = self.xvfb_metrics
|
15079
|
+
metrics_string = metrics_string.replace(" ", "")
|
15080
|
+
metrics_list = metrics_string.split(",")[0:2]
|
15081
|
+
exception_string = (
|
15082
|
+
"Invalid input for xvfb_metrics!\n"
|
15083
|
+
"Expecting a comma-separated string\n"
|
15084
|
+
"with integer values for Width/Height.\n"
|
15085
|
+
'Eg. --xvfb-metrics="1920,1080".\n'
|
15086
|
+
"(Minimum: 1024,768) (Default: 1366,768)"
|
15087
|
+
)
|
15088
|
+
if len(metrics_list) != 2:
|
15089
|
+
raise Exception(exception_string)
|
15090
|
+
try:
|
15091
|
+
self._xvfb_width = int(metrics_list[0])
|
15092
|
+
self._xvfb_height = int(metrics_list[1])
|
15093
|
+
# The minimum width,height is: 1024,768
|
15094
|
+
if self._xvfb_width < 1024:
|
15095
|
+
self._xvfb_width = 1024
|
15096
|
+
sb_config._xvfb_width = self._xvfb_width
|
15097
|
+
if self._xvfb_height < 768:
|
15098
|
+
self._xvfb_height = 768
|
15099
|
+
sb_config._xvfb_height = self._xvfb_height
|
15100
|
+
self.xvfb = True
|
15101
|
+
except Exception:
|
15102
|
+
raise Exception(exception_string)
|
15103
|
+
|
14544
15104
|
if self.mobile_emulator and not self.user_agent:
|
14545
15105
|
# Use a Pixel user agent by default if not specified
|
14546
15106
|
self.user_agent = constants.Mobile.AGENT
|
15107
|
+
|
14547
15108
|
if self.browser in ["firefox", "ie", "safari"]:
|
14548
15109
|
# The Recorder Mode browser extension is only for Chrome/Edge.
|
14549
15110
|
if self.recorder_mode:
|
@@ -14553,10 +15114,18 @@ class BaseCase(unittest.TestCase):
|
|
14553
15114
|
)
|
14554
15115
|
raise Exception(message)
|
14555
15116
|
|
15117
|
+
if not hasattr(self, "is_nosetest") or not self.is_nosetest:
|
15118
|
+
# Xvfb Virtual Display activation for Linux
|
15119
|
+
self.__activate_virtual_display_as_needed()
|
15120
|
+
|
14556
15121
|
# Dashboard pre-processing:
|
14557
15122
|
if self.dashboard:
|
14558
15123
|
if self._multithreaded:
|
14559
15124
|
with self.dash_lock:
|
15125
|
+
with suppress(Exception):
|
15126
|
+
shared_utils.make_writable(
|
15127
|
+
constants.Dashboard.LOCKFILE
|
15128
|
+
)
|
14560
15129
|
if not self._dash_initialized:
|
14561
15130
|
sb_config._dashboard_initialized = True
|
14562
15131
|
self._dash_initialized = True
|
@@ -14577,7 +15146,7 @@ class BaseCase(unittest.TestCase):
|
|
14577
15146
|
if not hasattr(sb_config, "shared_driver"):
|
14578
15147
|
sb_config.shared_driver = None
|
14579
15148
|
if sb_config.shared_driver:
|
14580
|
-
|
15149
|
+
with suppress(Exception):
|
14581
15150
|
self._default_driver = sb_config.shared_driver
|
14582
15151
|
self.driver = sb_config.shared_driver
|
14583
15152
|
self._drivers_list = [sb_config.shared_driver]
|
@@ -14591,12 +15160,8 @@ class BaseCase(unittest.TestCase):
|
|
14591
15160
|
self.switch_to_window(0)
|
14592
15161
|
if self._crumbs:
|
14593
15162
|
self.wait_for_ready_state_complete()
|
14594
|
-
|
15163
|
+
with suppress(Exception):
|
14595
15164
|
self.driver.delete_all_cookies()
|
14596
|
-
except Exception:
|
14597
|
-
pass
|
14598
|
-
except Exception:
|
14599
|
-
pass
|
14600
15165
|
if self._reuse_session and sb_config.shared_driver and has_url:
|
14601
15166
|
good_start_page = False
|
14602
15167
|
if self.recorder_ext:
|
@@ -14639,6 +15204,7 @@ class BaseCase(unittest.TestCase):
|
|
14639
15204
|
cap_file=self.cap_file,
|
14640
15205
|
cap_string=self.cap_string,
|
14641
15206
|
recorder_ext=self.recorder_ext,
|
15207
|
+
disable_cookies=self.disable_cookies,
|
14642
15208
|
disable_js=self.disable_js,
|
14643
15209
|
disable_csp=self.disable_csp,
|
14644
15210
|
enable_ws=self.enable_ws,
|
@@ -14650,6 +15216,7 @@ class BaseCase(unittest.TestCase):
|
|
14650
15216
|
log_cdp_events=self.log_cdp_events,
|
14651
15217
|
no_sandbox=self.no_sandbox,
|
14652
15218
|
disable_gpu=self.disable_gpu,
|
15219
|
+
headless1=self.headless1,
|
14653
15220
|
headless2=self.headless2,
|
14654
15221
|
incognito=self.incognito,
|
14655
15222
|
guest_mode=self.guest_mode,
|
@@ -14683,10 +15250,8 @@ class BaseCase(unittest.TestCase):
|
|
14683
15250
|
if self.driver.timeouts.implicit_wait > 0:
|
14684
15251
|
self.driver.implicitly_wait(0)
|
14685
15252
|
except Exception:
|
14686
|
-
|
15253
|
+
with suppress(Exception):
|
14687
15254
|
self.driver.implicitly_wait(0)
|
14688
|
-
except Exception:
|
14689
|
-
pass
|
14690
15255
|
self._default_driver = self.driver
|
14691
15256
|
if self._reuse_session:
|
14692
15257
|
sb_config.shared_driver = self.driver
|
@@ -14705,13 +15270,11 @@ class BaseCase(unittest.TestCase):
|
|
14705
15270
|
self.set_time_limit(self.time_limit)
|
14706
15271
|
|
14707
15272
|
# Configure the page load timeout
|
14708
|
-
|
15273
|
+
with suppress(Exception):
|
14709
15274
|
if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
|
14710
15275
|
self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
|
14711
15276
|
else:
|
14712
15277
|
self.driver.set_page_load_timeout(120) # Selenium uses 300
|
14713
|
-
except Exception:
|
14714
|
-
pass
|
14715
15278
|
|
14716
15279
|
# Set the start time for the test (in ms).
|
14717
15280
|
# Although the pytest clock starts before setUp() begins,
|
@@ -14740,7 +15303,7 @@ class BaseCase(unittest.TestCase):
|
|
14740
15303
|
not self.__last_page_screenshot
|
14741
15304
|
and not self.__last_page_screenshot_png
|
14742
15305
|
):
|
14743
|
-
|
15306
|
+
with suppress(Exception):
|
14744
15307
|
try:
|
14745
15308
|
element = page_actions.wait_for_element_visible(
|
14746
15309
|
self.driver,
|
@@ -14770,14 +15333,10 @@ class BaseCase(unittest.TestCase):
|
|
14770
15333
|
element.screenshot_as_base64
|
14771
15334
|
)
|
14772
15335
|
except Exception:
|
14773
|
-
|
15336
|
+
with suppress(Exception):
|
14774
15337
|
self.__last_page_screenshot = (
|
14775
15338
|
self.driver.get_screenshot_as_base64()
|
14776
15339
|
)
|
14777
|
-
except Exception:
|
14778
|
-
pass
|
14779
|
-
except Exception:
|
14780
|
-
pass
|
14781
15340
|
if not self.__last_page_screenshot:
|
14782
15341
|
self.__last_page_screenshot = SCREENSHOT_UNDEFINED
|
14783
15342
|
self.__last_page_screenshot_png = SCREENSHOT_UNDEFINED
|
@@ -14787,12 +15346,10 @@ class BaseCase(unittest.TestCase):
|
|
14787
15346
|
element.screenshot_as_png
|
14788
15347
|
)
|
14789
15348
|
except Exception:
|
14790
|
-
|
15349
|
+
with suppress(Exception):
|
14791
15350
|
self.__last_page_screenshot_png = (
|
14792
15351
|
self.driver.get_screenshot_as_png()
|
14793
15352
|
)
|
14794
|
-
except Exception:
|
14795
|
-
pass
|
14796
15353
|
else:
|
14797
15354
|
import base64
|
14798
15355
|
|
@@ -14807,12 +15364,10 @@ class BaseCase(unittest.TestCase):
|
|
14807
15364
|
element.screenshot_as_png
|
14808
15365
|
)
|
14809
15366
|
except Exception:
|
14810
|
-
|
15367
|
+
with suppress(Exception):
|
14811
15368
|
self.__last_page_screenshot_png = (
|
14812
15369
|
self.driver.get_screenshot_as_png()
|
14813
15370
|
)
|
14814
|
-
except Exception:
|
14815
|
-
pass
|
14816
15371
|
sb_config._last_page_screenshot_png = self.__last_page_screenshot_png
|
14817
15372
|
|
14818
15373
|
def __set_last_page_url(self):
|
@@ -14864,7 +15419,6 @@ class BaseCase(unittest.TestCase):
|
|
14864
15419
|
data_payload.state = state
|
14865
15420
|
if err:
|
14866
15421
|
import traceback
|
14867
|
-
|
14868
15422
|
tb_string = traceback.format_exc()
|
14869
15423
|
if "Message: " in tb_string:
|
14870
15424
|
data_payload.message = (
|
@@ -14899,7 +15453,7 @@ class BaseCase(unittest.TestCase):
|
|
14899
15453
|
|
14900
15454
|
def __add_pytest_html_extra(self):
|
14901
15455
|
if not self.__added_pytest_html_extra:
|
14902
|
-
|
15456
|
+
with suppress(Exception):
|
14903
15457
|
if self.with_selenium:
|
14904
15458
|
if not self.__last_page_screenshot:
|
14905
15459
|
self.__set_last_page_screenshot()
|
@@ -14926,8 +15480,6 @@ class BaseCase(unittest.TestCase):
|
|
14926
15480
|
):
|
14927
15481
|
self._html_report_extra.append(extra_url)
|
14928
15482
|
self._html_report_extra.append(extra_image)
|
14929
|
-
except Exception:
|
14930
|
-
pass
|
14931
15483
|
|
14932
15484
|
def __delay_driver_quit(self):
|
14933
15485
|
delay_driver_quit = False
|
@@ -15021,7 +15573,6 @@ class BaseCase(unittest.TestCase):
|
|
15021
15573
|
context_id = None
|
15022
15574
|
if filename == "base_case.py" or methodname == "runTest":
|
15023
15575
|
import traceback
|
15024
|
-
|
15025
15576
|
stack_base = traceback.format_stack()[0].split(", in ")[0]
|
15026
15577
|
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
|
15027
15578
|
if hasattr(self, "cm_filename") and self.cm_filename:
|
@@ -15041,7 +15592,8 @@ class BaseCase(unittest.TestCase):
|
|
15041
15592
|
elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
|
15042
15593
|
test_id = sb_config._latest_display_id
|
15043
15594
|
test_id = test_id.replace(".py::", ".").replace("::", ".")
|
15044
|
-
test_id = test_id.replace("/", ".").replace("
|
15595
|
+
test_id = test_id.replace("/", ".").replace("\\", ".")
|
15596
|
+
test_id = test_id.replace(" ", "_")
|
15045
15597
|
# Linux filename length limit for `codecs.open(filename)` = 255
|
15046
15598
|
# 255 - len("latest_logs/") - len("/basic_test_info.txt") = 223
|
15047
15599
|
if len(test_id) <= 223:
|
@@ -15133,6 +15685,8 @@ class BaseCase(unittest.TestCase):
|
|
15133
15685
|
constants.Dashboard.LOCKFILE
|
15134
15686
|
)
|
15135
15687
|
with self.dash_lock:
|
15688
|
+
with suppress(Exception):
|
15689
|
+
shared_utils.make_writable(constants.Dashboard.LOCKFILE)
|
15136
15690
|
self.__process_dashboard(has_exception, init)
|
15137
15691
|
else:
|
15138
15692
|
self.__process_dashboard(has_exception, init)
|
@@ -15616,6 +16170,31 @@ class BaseCase(unittest.TestCase):
|
|
15616
16170
|
else:
|
15617
16171
|
return None
|
15618
16172
|
|
16173
|
+
def _get_num_handles(self):
|
16174
|
+
return len(self.driver.window_handles)
|
16175
|
+
|
16176
|
+
def _get_rec_shift_esc_script(self):
|
16177
|
+
return (
|
16178
|
+
"""document.onkeydown = function(evt) {
|
16179
|
+
evt = evt || window.event;
|
16180
|
+
var isEscape = false;
|
16181
|
+
if ("key" in evt) {
|
16182
|
+
isEscape = (evt.key === "Escape" || evt.key === "Esc");
|
16183
|
+
last_key = evt.key;
|
16184
|
+
} else {
|
16185
|
+
isEscape = (evt.keyCode === 27);
|
16186
|
+
last_key = evt.keyCode;
|
16187
|
+
if (last_key === 16) {
|
16188
|
+
last_key = "Shift";
|
16189
|
+
}
|
16190
|
+
}
|
16191
|
+
if (isEscape && document.sb_last_key === "Shift") {
|
16192
|
+
document.sb_esc_end = "yes";
|
16193
|
+
}
|
16194
|
+
document.sb_last_key = last_key;
|
16195
|
+
};"""
|
16196
|
+
)
|
16197
|
+
|
15619
16198
|
def _addSkip(self, result, test_case, reason):
|
15620
16199
|
"""This method should NOT be called directly from tests."""
|
15621
16200
|
addSkip = getattr(result, 'addSkip', None)
|
@@ -15713,7 +16292,15 @@ class BaseCase(unittest.TestCase):
|
|
15713
16292
|
# This test already called tearDown()
|
15714
16293
|
return
|
15715
16294
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
15716
|
-
self.
|
16295
|
+
page_actions._reconnect_if_disconnected(self.driver)
|
16296
|
+
try:
|
16297
|
+
self.__process_recorded_actions()
|
16298
|
+
except Exception as e:
|
16299
|
+
print("\n (Recorder) Code-generation exception:")
|
16300
|
+
if hasattr(e, "msg"):
|
16301
|
+
print("\n" + str(e.msg))
|
16302
|
+
else:
|
16303
|
+
print(e)
|
15717
16304
|
self.__called_teardown = True
|
15718
16305
|
self.__called_setup = False
|
15719
16306
|
try:
|
@@ -15746,6 +16333,7 @@ class BaseCase(unittest.TestCase):
|
|
15746
16333
|
)
|
15747
16334
|
raise Exception(message)
|
15748
16335
|
# *** Start tearDown() officially ***
|
16336
|
+
page_actions._reconnect_if_disconnected(self.driver)
|
15749
16337
|
self.__slow_mode_pause_if_active()
|
15750
16338
|
has_exception = self.__has_exception()
|
15751
16339
|
sb_config._has_exception = has_exception
|
@@ -15868,6 +16456,10 @@ class BaseCase(unittest.TestCase):
|
|
15868
16456
|
if self.dashboard:
|
15869
16457
|
if self._multithreaded:
|
15870
16458
|
with self.dash_lock:
|
16459
|
+
with suppress(Exception):
|
16460
|
+
shared_utils.make_writable(
|
16461
|
+
constants.Dashboard.LOCKFILE
|
16462
|
+
)
|
15871
16463
|
self.__process_dashboard(has_exception)
|
15872
16464
|
else:
|
15873
16465
|
self.__process_dashboard(has_exception)
|
@@ -15935,7 +16527,6 @@ class BaseCase(unittest.TestCase):
|
|
15935
16527
|
else:
|
15936
16528
|
# (Pynose / Behave / Pure Python)
|
15937
16529
|
if hasattr(self, "is_behave") and self.is_behave:
|
15938
|
-
import colorama
|
15939
16530
|
if sb_config.behave_scenario.status.name == "failed":
|
15940
16531
|
has_exception = True
|
15941
16532
|
sb_config._has_exception = True
|
@@ -15943,8 +16534,6 @@ class BaseCase(unittest.TestCase):
|
|
15943
16534
|
if is_windows:
|
15944
16535
|
c1 = colorama.Fore.RED + colorama.Back.LIGHTRED_EX
|
15945
16536
|
cr = colorama.Style.RESET_ALL
|
15946
|
-
if hasattr(colorama, "just_fix_windows_console"):
|
15947
|
-
colorama.just_fix_windows_console()
|
15948
16537
|
msg = msg.replace("❌", c1 + "><" + cr)
|
15949
16538
|
print(msg)
|
15950
16539
|
else:
|
@@ -15952,8 +16541,6 @@ class BaseCase(unittest.TestCase):
|
|
15952
16541
|
if is_windows:
|
15953
16542
|
c2 = colorama.Fore.GREEN + colorama.Back.LIGHTGREEN_EX
|
15954
16543
|
cr = colorama.Style.RESET_ALL
|
15955
|
-
if hasattr(colorama, "just_fix_windows_console"):
|
15956
|
-
colorama.just_fix_windows_console()
|
15957
16544
|
msg = msg.replace("✅", c2 + "<>" + cr)
|
15958
16545
|
print(msg)
|
15959
16546
|
if self.dashboard:
|
@@ -16018,6 +16605,7 @@ class BaseCase(unittest.TestCase):
|
|
16018
16605
|
self.__quit_all_drivers()
|
16019
16606
|
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
|
16020
16607
|
if hasattr(self, "_xvfb_display") and self._xvfb_display:
|
16608
|
+
# Stop the Xvfb virtual display launched from BaseCase
|
16021
16609
|
try:
|
16022
16610
|
if hasattr(self._xvfb_display, "stop"):
|
16023
16611
|
self._xvfb_display.stop()
|
@@ -16027,6 +16615,20 @@ class BaseCase(unittest.TestCase):
|
|
16027
16615
|
pass
|
16028
16616
|
except Exception:
|
16029
16617
|
pass
|
16618
|
+
if (
|
16619
|
+
hasattr(sb_config, "_virtual_display")
|
16620
|
+
and sb_config._virtual_display
|
16621
|
+
and hasattr(sb_config._virtual_display, "stop")
|
16622
|
+
):
|
16623
|
+
# CDP Mode may launch a 2nd Xvfb virtual display
|
16624
|
+
try:
|
16625
|
+
sb_config._virtual_display.stop()
|
16626
|
+
sb_config._virtual_display = None
|
16627
|
+
sb_config.headless_active = False
|
16628
|
+
except AttributeError:
|
16629
|
+
pass
|
16630
|
+
except Exception:
|
16631
|
+
pass
|
16030
16632
|
if self.__visual_baseline_copies:
|
16031
16633
|
sb_config._visual_baseline_copies = True
|
16032
16634
|
if has_exception:
|