seleniumbase 4.24.10__py3-none-any.whl → 4.33.15__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|