seleniumbase 4.24.11__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/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 +1225 -614
- 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.11.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
- {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
- {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +67 -69
- {seleniumbase-4.24.11.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.11.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.24.11.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,29 +1310,32 @@ class BaseCase(unittest.TestCase):
|
|
1310
1310
|
return self.get_page_title()
|
1311
1311
|
|
1312
1312
|
def get_user_agent(self):
|
1313
|
+
if self.__is_cdp_swap_needed():
|
1314
|
+
return self.cdp.get_user_agent()
|
1313
1315
|
return self.execute_script("return navigator.userAgent;")
|
1314
1316
|
|
1315
1317
|
def get_locale_code(self):
|
1318
|
+
if self.__is_cdp_swap_needed():
|
1319
|
+
return self.cdp.get_locale_code()
|
1316
1320
|
return self.execute_script(
|
1317
1321
|
"return navigator.language || navigator.languages[0];"
|
1318
1322
|
)
|
1319
1323
|
|
1320
1324
|
def go_back(self):
|
1321
1325
|
self.__check_scope()
|
1326
|
+
if self.__is_cdp_swap_needed():
|
1327
|
+
self.cdp.go_back()
|
1328
|
+
return
|
1322
1329
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
1323
1330
|
self.save_recorded_actions()
|
1324
1331
|
pre_action_url = None
|
1325
|
-
|
1332
|
+
with suppress(Exception):
|
1326
1333
|
pre_action_url = self.driver.current_url
|
1327
|
-
except Exception:
|
1328
|
-
pass
|
1329
1334
|
self.__last_page_load_url = None
|
1330
1335
|
self.driver.back()
|
1331
|
-
|
1336
|
+
with suppress(Exception):
|
1332
1337
|
if pre_action_url == self.driver.current_url:
|
1333
1338
|
self.driver.back() # Again because the page was redirected
|
1334
|
-
except Exception:
|
1335
|
-
pass
|
1336
1339
|
if self.recorder_mode:
|
1337
1340
|
time_stamp = self.execute_script("return Date.now();")
|
1338
1341
|
origin = self.get_origin()
|
@@ -1348,6 +1351,9 @@ class BaseCase(unittest.TestCase):
|
|
1348
1351
|
|
1349
1352
|
def go_forward(self):
|
1350
1353
|
self.__check_scope()
|
1354
|
+
if self.__is_cdp_swap_needed():
|
1355
|
+
self.cdp.go_forward()
|
1356
|
+
return
|
1351
1357
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
1352
1358
|
self.save_recorded_actions()
|
1353
1359
|
self.__last_page_load_url = None
|
@@ -1401,7 +1407,7 @@ class BaseCase(unittest.TestCase):
|
|
1401
1407
|
to convert the open() action into open_if_not_url() so that the
|
1402
1408
|
same page isn't opened again if the user is already on the page."""
|
1403
1409
|
self.__check_scope()
|
1404
|
-
current_url = self.
|
1410
|
+
current_url = self.get_current_url()
|
1405
1411
|
if current_url != url:
|
1406
1412
|
if (
|
1407
1413
|
"?q=" not in current_url
|
@@ -1412,6 +1418,9 @@ class BaseCase(unittest.TestCase):
|
|
1412
1418
|
self.open(url)
|
1413
1419
|
|
1414
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)
|
1415
1424
|
self.wait_for_ready_state_complete()
|
1416
1425
|
selector, by = self.__recalculate_selector(selector, by)
|
1417
1426
|
if self.__is_shadow_selector(selector):
|
@@ -1419,6 +1428,9 @@ class BaseCase(unittest.TestCase):
|
|
1419
1428
|
return page_actions.is_element_present(self.driver, selector, by)
|
1420
1429
|
|
1421
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)
|
1422
1434
|
self.wait_for_ready_state_complete()
|
1423
1435
|
selector, by = self.__recalculate_selector(selector, by)
|
1424
1436
|
if self.__is_shadow_selector(selector):
|
@@ -1439,7 +1451,8 @@ class BaseCase(unittest.TestCase):
|
|
1439
1451
|
return self.__is_shadow_element_enabled(selector)
|
1440
1452
|
return page_actions.is_element_enabled(self.driver, selector, by)
|
1441
1453
|
|
1442
|
-
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."""
|
1443
1456
|
self.wait_for_ready_state_complete()
|
1444
1457
|
time.sleep(0.01)
|
1445
1458
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -1447,7 +1460,9 @@ class BaseCase(unittest.TestCase):
|
|
1447
1460
|
return self.__is_shadow_text_visible(text, selector)
|
1448
1461
|
return page_actions.is_text_visible(self.driver, text, selector, by)
|
1449
1462
|
|
1450
|
-
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.)"""
|
1451
1466
|
self.wait_for_ready_state_complete()
|
1452
1467
|
time.sleep(0.01)
|
1453
1468
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -1457,7 +1472,7 @@ class BaseCase(unittest.TestCase):
|
|
1457
1472
|
self.driver, text, selector, by
|
1458
1473
|
)
|
1459
1474
|
|
1460
|
-
def is_non_empty_text_visible(self, selector="
|
1475
|
+
def is_non_empty_text_visible(self, selector="body", by="css selector"):
|
1461
1476
|
"""Returns whether the element has any non-empty text visible.
|
1462
1477
|
Whitespace-only text is considered empty text."""
|
1463
1478
|
self.wait_for_ready_state_complete()
|
@@ -1486,6 +1501,7 @@ class BaseCase(unittest.TestCase):
|
|
1486
1501
|
)
|
1487
1502
|
|
1488
1503
|
def is_link_text_visible(self, link_text):
|
1504
|
+
"""Returns whether there's an exact match for the link text."""
|
1489
1505
|
self.wait_for_ready_state_complete()
|
1490
1506
|
time.sleep(0.01)
|
1491
1507
|
return page_actions.is_element_visible(
|
@@ -1493,6 +1509,7 @@ class BaseCase(unittest.TestCase):
|
|
1493
1509
|
)
|
1494
1510
|
|
1495
1511
|
def is_partial_link_text_visible(self, partial_link_text):
|
1512
|
+
"""Returns whether there's a substring match for the link text."""
|
1496
1513
|
self.wait_for_ready_state_complete()
|
1497
1514
|
time.sleep(0.01)
|
1498
1515
|
return page_actions.is_element_visible(
|
@@ -1585,11 +1602,18 @@ class BaseCase(unittest.TestCase):
|
|
1585
1602
|
def click_link_text(self, link_text, timeout=None):
|
1586
1603
|
"""This method clicks link text on a page."""
|
1587
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()
|
1588
1609
|
if not timeout:
|
1589
1610
|
timeout = settings.SMALL_TIMEOUT
|
1590
1611
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
1591
1612
|
timeout = self.__get_new_timeout(timeout)
|
1592
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
|
1593
1617
|
if self.browser == "safari":
|
1594
1618
|
if self.demo_mode:
|
1595
1619
|
self.wait_for_link_text_present(link_text, timeout=timeout)
|
@@ -1620,10 +1644,8 @@ class BaseCase(unittest.TestCase):
|
|
1620
1644
|
if self.__needs_minimum_wait():
|
1621
1645
|
time.sleep(0.04)
|
1622
1646
|
pre_action_url = None
|
1623
|
-
|
1647
|
+
with suppress(Exception):
|
1624
1648
|
pre_action_url = self.driver.current_url
|
1625
|
-
except Exception:
|
1626
|
-
pass
|
1627
1649
|
pre_window_count = len(self.driver.window_handles)
|
1628
1650
|
try:
|
1629
1651
|
element = self.wait_for_link_text_visible(link_text, timeout=0.2)
|
@@ -1694,10 +1716,8 @@ class BaseCase(unittest.TestCase):
|
|
1694
1716
|
# switch to the last one if it exists.
|
1695
1717
|
self.switch_to_window(-1)
|
1696
1718
|
if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
|
1697
|
-
|
1719
|
+
with suppress(Exception):
|
1698
1720
|
self.wait_for_ready_state_complete()
|
1699
|
-
except Exception:
|
1700
|
-
pass
|
1701
1721
|
if self.demo_mode:
|
1702
1722
|
if self.driver.current_url != pre_action_url:
|
1703
1723
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -1718,15 +1738,16 @@ class BaseCase(unittest.TestCase):
|
|
1718
1738
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
1719
1739
|
timeout = self.__get_new_timeout(timeout)
|
1720
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
|
1721
1744
|
if not self.is_partial_link_text_present(partial_link_text):
|
1722
1745
|
self.wait_for_partial_link_text_present(
|
1723
1746
|
partial_link_text, timeout=timeout
|
1724
1747
|
)
|
1725
1748
|
pre_action_url = None
|
1726
|
-
|
1749
|
+
with suppress(Exception):
|
1727
1750
|
pre_action_url = self.driver.current_url
|
1728
|
-
except Exception:
|
1729
|
-
pass
|
1730
1751
|
pre_window_count = len(self.driver.window_handles)
|
1731
1752
|
try:
|
1732
1753
|
element = self.wait_for_partial_link_text(
|
@@ -1809,10 +1830,8 @@ class BaseCase(unittest.TestCase):
|
|
1809
1830
|
# switch to the last one if it exists.
|
1810
1831
|
self.switch_to_window(-1)
|
1811
1832
|
if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:
|
1812
|
-
|
1833
|
+
with suppress(Exception):
|
1813
1834
|
self.wait_for_ready_state_complete()
|
1814
|
-
except Exception:
|
1815
|
-
pass
|
1816
1835
|
if self.demo_mode:
|
1817
1836
|
if self.driver.current_url != pre_action_url:
|
1818
1837
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -1823,13 +1842,15 @@ class BaseCase(unittest.TestCase):
|
|
1823
1842
|
elif self.slow_mode:
|
1824
1843
|
self.__slow_mode_pause_if_active()
|
1825
1844
|
|
1826
|
-
def get_text(self, selector, by="css selector", timeout=None):
|
1845
|
+
def get_text(self, selector="body", by="css selector", timeout=None):
|
1827
1846
|
self.__check_scope()
|
1828
1847
|
if not timeout:
|
1829
1848
|
timeout = settings.LARGE_TIMEOUT
|
1830
1849
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1831
1850
|
timeout = self.__get_new_timeout(timeout)
|
1832
1851
|
selector, by = self.__recalculate_selector(selector, by)
|
1852
|
+
if self.__is_cdp_swap_needed():
|
1853
|
+
return self.cdp.get_text(selector)
|
1833
1854
|
if self.__is_shadow_selector(selector):
|
1834
1855
|
return self.__get_shadow_text(selector, timeout)
|
1835
1856
|
self.wait_for_ready_state_complete()
|
@@ -1879,6 +1900,8 @@ class BaseCase(unittest.TestCase):
|
|
1879
1900
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
1880
1901
|
timeout = self.__get_new_timeout(timeout)
|
1881
1902
|
selector, by = self.__recalculate_selector(selector, by)
|
1903
|
+
if self.__is_cdp_swap_needed():
|
1904
|
+
return self.cdp.get_element_attribute(selector, attribute)
|
1882
1905
|
self.wait_for_ready_state_complete()
|
1883
1906
|
time.sleep(0.01)
|
1884
1907
|
if self.__is_shadow_selector(selector):
|
@@ -1928,10 +1951,8 @@ class BaseCase(unittest.TestCase):
|
|
1928
1951
|
original_attribute = attribute
|
1929
1952
|
original_value = value
|
1930
1953
|
if scroll and self.is_element_visible(selector, by=by):
|
1931
|
-
|
1954
|
+
with suppress(Exception):
|
1932
1955
|
self.scroll_to(selector, by=by, timeout=timeout)
|
1933
|
-
except Exception:
|
1934
|
-
pass
|
1935
1956
|
attribute = re.escape(attribute)
|
1936
1957
|
attribute = self.__escape_quotes_if_needed(attribute)
|
1937
1958
|
value = re.escape(value)
|
@@ -1959,6 +1980,9 @@ class BaseCase(unittest.TestCase):
|
|
1959
1980
|
self.set_attributes("a", "href", "https://google.com")"""
|
1960
1981
|
self.__check_scope()
|
1961
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
|
1962
1986
|
original_attribute = attribute
|
1963
1987
|
original_value = value
|
1964
1988
|
attribute = re.escape(attribute)
|
@@ -1976,10 +2000,8 @@ class BaseCase(unittest.TestCase):
|
|
1976
2000
|
attribute,
|
1977
2001
|
value,
|
1978
2002
|
)
|
1979
|
-
|
2003
|
+
with suppress(Exception):
|
1980
2004
|
self.execute_script(script)
|
1981
|
-
except Exception:
|
1982
|
-
pass
|
1983
2005
|
if self.recorder_mode and self.__current_url_is_recordable():
|
1984
2006
|
if self.get_session_storage_item("pause_recorder") == "no":
|
1985
2007
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -2008,10 +2030,8 @@ class BaseCase(unittest.TestCase):
|
|
2008
2030
|
timeout = self.__get_new_timeout(timeout)
|
2009
2031
|
selector, by = self.__recalculate_selector(selector, by)
|
2010
2032
|
if self.is_element_visible(selector, by=by):
|
2011
|
-
|
2033
|
+
with suppress(Exception):
|
2012
2034
|
self.scroll_to(selector, by=by, timeout=timeout)
|
2013
|
-
except Exception:
|
2014
|
-
pass
|
2015
2035
|
attribute = re.escape(attribute)
|
2016
2036
|
attribute = self.__escape_quotes_if_needed(attribute)
|
2017
2037
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
@@ -2040,10 +2060,16 @@ class BaseCase(unittest.TestCase):
|
|
2040
2060
|
css_selector,
|
2041
2061
|
attribute,
|
2042
2062
|
)
|
2043
|
-
|
2063
|
+
with suppress(Exception):
|
2044
2064
|
self.execute_script(script)
|
2045
|
-
|
2046
|
-
|
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")
|
2047
2073
|
|
2048
2074
|
def get_property(
|
2049
2075
|
self, selector, property, by="css selector", timeout=None
|
@@ -2078,7 +2104,9 @@ class BaseCase(unittest.TestCase):
|
|
2078
2104
|
return ""
|
2079
2105
|
return property_value
|
2080
2106
|
|
2081
|
-
def get_text_content(
|
2107
|
+
def get_text_content(
|
2108
|
+
self, selector="body", by="css selector", timeout=None
|
2109
|
+
):
|
2082
2110
|
"""Returns the text that appears in the HTML for an element.
|
2083
2111
|
This is different from "self.get_text(selector, by="css selector")"
|
2084
2112
|
because that only returns the visible text on a page for an element,
|
@@ -2146,6 +2174,11 @@ class BaseCase(unittest.TestCase):
|
|
2146
2174
|
Elements could be either hidden or visible on the page.
|
2147
2175
|
If "limit" is set and > 0, will only return that many elements."""
|
2148
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
|
2149
2182
|
self.wait_for_ready_state_complete()
|
2150
2183
|
time.sleep(0.05)
|
2151
2184
|
elements = self.driver.find_elements(by=by, value=selector)
|
@@ -2157,6 +2190,11 @@ class BaseCase(unittest.TestCase):
|
|
2157
2190
|
"""Returns a list of matching WebElements that are visible.
|
2158
2191
|
If "limit" is set and > 0, will only return that many elements."""
|
2159
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
|
2160
2198
|
self.wait_for_ready_state_complete()
|
2161
2199
|
time.sleep(0.05)
|
2162
2200
|
return page_actions.find_visible_elements(
|
@@ -2179,6 +2217,9 @@ class BaseCase(unittest.TestCase):
|
|
2179
2217
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2180
2218
|
timeout = self.__get_new_timeout(timeout)
|
2181
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
|
2182
2223
|
self.wait_for_ready_state_complete()
|
2183
2224
|
if self.__needs_minimum_wait():
|
2184
2225
|
time.sleep(0.12)
|
@@ -2187,20 +2228,16 @@ class BaseCase(unittest.TestCase):
|
|
2187
2228
|
element = self.wait_for_element_present(
|
2188
2229
|
selector, by=by, timeout=timeout
|
2189
2230
|
)
|
2190
|
-
|
2231
|
+
with suppress(Exception):
|
2191
2232
|
# If the first element isn't visible, wait a little.
|
2192
2233
|
if not element.is_displayed():
|
2193
2234
|
time.sleep(0.16)
|
2194
2235
|
if self.undetectable:
|
2195
2236
|
time.sleep(0.06)
|
2196
|
-
except Exception:
|
2197
|
-
pass
|
2198
2237
|
elements = self.find_elements(selector, by=by)
|
2199
2238
|
pre_action_url = None
|
2200
|
-
|
2239
|
+
with suppress(Exception):
|
2201
2240
|
pre_action_url = self.driver.current_url
|
2202
|
-
except Exception:
|
2203
|
-
pass
|
2204
2241
|
pre_window_count = len(self.driver.window_handles)
|
2205
2242
|
click_count = 0
|
2206
2243
|
for element in elements:
|
@@ -2263,13 +2300,16 @@ class BaseCase(unittest.TestCase):
|
|
2263
2300
|
):
|
2264
2301
|
"""Finds all matching page elements and clicks the nth visible one.
|
2265
2302
|
Example: self.click_nth_visible_element('[type="checkbox"]', 5)
|
2266
|
-
|
2303
|
+
(Clicks the 5th visible checkbox on the page.)"""
|
2267
2304
|
self.__check_scope()
|
2268
2305
|
if not timeout:
|
2269
2306
|
timeout = settings.SMALL_TIMEOUT
|
2270
2307
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2271
2308
|
timeout = self.__get_new_timeout(timeout)
|
2272
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
|
2273
2313
|
self.wait_for_ready_state_complete()
|
2274
2314
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
2275
2315
|
elements = self.find_visible_elements(selector, by=by)
|
@@ -2283,10 +2323,8 @@ class BaseCase(unittest.TestCase):
|
|
2283
2323
|
number = 0
|
2284
2324
|
element = elements[number]
|
2285
2325
|
pre_action_url = None
|
2286
|
-
|
2326
|
+
with suppress(Exception):
|
2287
2327
|
pre_action_url = self.driver.current_url
|
2288
|
-
except Exception:
|
2289
|
-
pass
|
2290
2328
|
pre_window_count = len(self.driver.window_handles)
|
2291
2329
|
try:
|
2292
2330
|
self.__scroll_to_element(element)
|
@@ -2325,26 +2363,28 @@ class BaseCase(unittest.TestCase):
|
|
2325
2363
|
Use click_visible_elements() to click all matching elements.
|
2326
2364
|
If a "timeout" is provided, waits that long for the element
|
2327
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
|
2328
2369
|
self.wait_for_ready_state_complete()
|
2329
2370
|
if self.is_element_visible(selector, by=by):
|
2330
2371
|
self.click(selector, by=by)
|
2331
2372
|
elif timeout > 0:
|
2332
|
-
|
2373
|
+
with suppress(Exception):
|
2333
2374
|
self.wait_for_element_visible(
|
2334
2375
|
selector, by=by, timeout=timeout
|
2335
2376
|
)
|
2336
|
-
except Exception:
|
2337
|
-
pass
|
2338
2377
|
if self.is_element_visible(selector, by=by):
|
2339
2378
|
self.click(selector, by=by)
|
2340
2379
|
|
2341
2380
|
def click_active_element(self):
|
2381
|
+
if self.__is_cdp_swap_needed():
|
2382
|
+
self.cdp.click_active_element()
|
2383
|
+
return
|
2342
2384
|
self.wait_for_ready_state_complete()
|
2343
2385
|
pre_action_url = None
|
2344
|
-
|
2386
|
+
with suppress(Exception):
|
2345
2387
|
pre_action_url = self.driver.current_url
|
2346
|
-
except Exception:
|
2347
|
-
pass
|
2348
2388
|
pre_window_count = len(self.driver.window_handles)
|
2349
2389
|
if self.recorder_mode:
|
2350
2390
|
selector = js_utils.get_active_element_css(self.driver)
|
@@ -2448,16 +2488,14 @@ class BaseCase(unittest.TestCase):
|
|
2448
2488
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
2449
2489
|
timeout = self.__get_new_timeout(timeout)
|
2450
2490
|
selector, by = self.__recalculate_selector(selector, by)
|
2491
|
+
if self.__is_cdp_swap_needed():
|
2492
|
+
return self.cdp.is_checked(selector)
|
2451
2493
|
kind = self.get_attribute(selector, "type", by=by, timeout=timeout)
|
2452
2494
|
if kind != "checkbox" and kind != "radio":
|
2453
2495
|
raise Exception("Expecting a checkbox or a radio button element!")
|
2454
|
-
|
2496
|
+
return self.get_attribute(
|
2455
2497
|
selector, "checked", by=by, timeout=timeout, hard_fail=False
|
2456
2498
|
)
|
2457
|
-
if is_checked:
|
2458
|
-
return True
|
2459
|
-
else: # (NoneType)
|
2460
|
-
return False
|
2461
2499
|
|
2462
2500
|
def is_selected(self, selector, by="css selector", timeout=None):
|
2463
2501
|
"""Same as is_checked()"""
|
@@ -2467,6 +2505,9 @@ class BaseCase(unittest.TestCase):
|
|
2467
2505
|
"""If a checkbox or radio button is not checked, will check it."""
|
2468
2506
|
self.__check_scope()
|
2469
2507
|
selector, by = self.__recalculate_selector(selector, by)
|
2508
|
+
if self.__is_cdp_swap_needed():
|
2509
|
+
self.cdp.check_if_unchecked(selector)
|
2510
|
+
return
|
2470
2511
|
if not self.is_checked(selector, by=by):
|
2471
2512
|
if self.is_element_visible(selector, by=by):
|
2472
2513
|
self.click(selector, by=by)
|
@@ -2477,12 +2518,10 @@ class BaseCase(unittest.TestCase):
|
|
2477
2518
|
)
|
2478
2519
|
# Handle switches that sit on checkboxes with zero opacity:
|
2479
2520
|
# Change the opacity a bit to allow the click to succeed.
|
2480
|
-
|
2521
|
+
with suppress(Exception):
|
2481
2522
|
self.execute_script(
|
2482
2523
|
'arguments[0].style.opacity="0.001";', element
|
2483
2524
|
)
|
2484
|
-
except Exception:
|
2485
|
-
pass
|
2486
2525
|
if self.is_element_visible(selector, by=by):
|
2487
2526
|
self.click(selector, by=by)
|
2488
2527
|
else:
|
@@ -2490,14 +2529,12 @@ class BaseCase(unittest.TestCase):
|
|
2490
2529
|
self.__dont_record_js_click = True
|
2491
2530
|
self.js_click(selector, by="css selector")
|
2492
2531
|
self.__dont_record_js_click = False
|
2493
|
-
|
2532
|
+
with suppress(Exception):
|
2494
2533
|
self.execute_script(
|
2495
2534
|
'arguments[0].style.opacity="arguments[1]";',
|
2496
2535
|
element,
|
2497
2536
|
opacity,
|
2498
2537
|
)
|
2499
|
-
except Exception:
|
2500
|
-
pass
|
2501
2538
|
|
2502
2539
|
def select_if_unselected(self, selector, by="css selector"):
|
2503
2540
|
"""Same as check_if_unchecked()"""
|
@@ -2507,6 +2544,9 @@ class BaseCase(unittest.TestCase):
|
|
2507
2544
|
"""If a checkbox is checked, will uncheck it."""
|
2508
2545
|
self.__check_scope()
|
2509
2546
|
selector, by = self.__recalculate_selector(selector, by)
|
2547
|
+
if self.__is_cdp_swap_needed():
|
2548
|
+
self.cdp.uncheck_if_checked(selector)
|
2549
|
+
return
|
2510
2550
|
if self.is_checked(selector, by=by):
|
2511
2551
|
if self.is_element_visible(selector, by=by):
|
2512
2552
|
self.click(selector, by=by)
|
@@ -2517,12 +2557,10 @@ class BaseCase(unittest.TestCase):
|
|
2517
2557
|
)
|
2518
2558
|
# Handle switches that sit on checkboxes with zero opacity:
|
2519
2559
|
# Change the opacity a bit to allow the click to succeed.
|
2520
|
-
|
2560
|
+
with suppress(Exception):
|
2521
2561
|
self.execute_script(
|
2522
2562
|
'arguments[0].style.opacity="0.001";', element
|
2523
2563
|
)
|
2524
|
-
except Exception:
|
2525
|
-
pass
|
2526
2564
|
if self.is_element_visible(selector, by=by):
|
2527
2565
|
self.click(selector, by=by)
|
2528
2566
|
else:
|
@@ -2530,14 +2568,12 @@ class BaseCase(unittest.TestCase):
|
|
2530
2568
|
self.__dont_record_js_click = True
|
2531
2569
|
self.js_click(selector, by="css selector")
|
2532
2570
|
self.__dont_record_js_click = False
|
2533
|
-
|
2571
|
+
with suppress(Exception):
|
2534
2572
|
self.execute_script(
|
2535
2573
|
'arguments[0].style.opacity="arguments[1]";',
|
2536
2574
|
element,
|
2537
2575
|
opacity,
|
2538
2576
|
)
|
2539
|
-
except Exception:
|
2540
|
-
pass
|
2541
2577
|
|
2542
2578
|
def unselect_if_selected(self, selector, by="css selector"):
|
2543
2579
|
"""Same as uncheck_if_checked()"""
|
@@ -2596,14 +2632,12 @@ class BaseCase(unittest.TestCase):
|
|
2596
2632
|
iframe_identifier = '[class="%s"]' % iframe_class
|
2597
2633
|
else:
|
2598
2634
|
continue
|
2599
|
-
|
2635
|
+
with suppress(Exception):
|
2600
2636
|
self.switch_to_frame(iframe_identifier, timeout=1)
|
2601
2637
|
if self.__needs_minimum_wait():
|
2602
2638
|
time.sleep(0.02)
|
2603
2639
|
if self.is_element_present(selector, by=by):
|
2604
2640
|
return iframe_identifier
|
2605
|
-
except Exception:
|
2606
|
-
pass
|
2607
2641
|
self.switch_to_default_content()
|
2608
2642
|
if self.__needs_minimum_wait():
|
2609
2643
|
time.sleep(0.02)
|
@@ -2629,6 +2663,9 @@ class BaseCase(unittest.TestCase):
|
|
2629
2663
|
original_selector = selector
|
2630
2664
|
original_by = by
|
2631
2665
|
selector, by = self.__recalculate_selector(selector, by)
|
2666
|
+
if self.__is_cdp_swap_needed():
|
2667
|
+
self.cdp.gui_hover_element(selector)
|
2668
|
+
return
|
2632
2669
|
self.wait_for_element_visible(
|
2633
2670
|
original_selector, by=original_by, timeout=timeout
|
2634
2671
|
)
|
@@ -2671,16 +2708,17 @@ class BaseCase(unittest.TestCase):
|
|
2671
2708
|
click_selector, click_by = self.__recalculate_selector(
|
2672
2709
|
click_selector, click_by
|
2673
2710
|
)
|
2711
|
+
if self.__is_cdp_swap_needed():
|
2712
|
+
self.cdp.gui_hover_and_click(hover_selector, click_selector)
|
2713
|
+
return
|
2674
2714
|
dropdown_element = self.wait_for_element_visible(
|
2675
2715
|
original_selector, by=original_by, timeout=timeout
|
2676
2716
|
)
|
2677
2717
|
self.__demo_mode_highlight_if_active(original_selector, original_by)
|
2678
2718
|
self.scroll_to(hover_selector, by=hover_by)
|
2679
2719
|
pre_action_url = None
|
2680
|
-
|
2720
|
+
with suppress(Exception):
|
2681
2721
|
pre_action_url = self.driver.current_url
|
2682
|
-
except Exception:
|
2683
|
-
pass
|
2684
2722
|
pre_window_count = len(self.driver.window_handles)
|
2685
2723
|
if self.recorder_mode and self.__current_url_is_recordable():
|
2686
2724
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -2744,10 +2782,8 @@ class BaseCase(unittest.TestCase):
|
|
2744
2782
|
self.__switch_to_newest_window_if_not_blank()
|
2745
2783
|
elif self.browser == "safari":
|
2746
2784
|
# Release the hover by hovering elsewhere
|
2747
|
-
|
2785
|
+
with suppress(Exception):
|
2748
2786
|
page_actions.hover_on_element(self.driver, "body")
|
2749
|
-
except Exception:
|
2750
|
-
pass
|
2751
2787
|
if self.demo_mode:
|
2752
2788
|
if self.driver.current_url != pre_action_url:
|
2753
2789
|
if not js_utils.is_jquery_activated(self.driver):
|
@@ -2807,10 +2843,8 @@ class BaseCase(unittest.TestCase):
|
|
2807
2843
|
self.__demo_mode_highlight_if_active(original_selector, original_by)
|
2808
2844
|
self.scroll_to(hover_selector, by=hover_by)
|
2809
2845
|
pre_action_url = None
|
2810
|
-
|
2846
|
+
with suppress(Exception):
|
2811
2847
|
pre_action_url = self.driver.current_url
|
2812
|
-
except Exception:
|
2813
|
-
pass
|
2814
2848
|
pre_window_count = len(self.driver.window_handles)
|
2815
2849
|
outdated_driver = False
|
2816
2850
|
element = None
|
@@ -2871,7 +2905,7 @@ class BaseCase(unittest.TestCase):
|
|
2871
2905
|
timeout=None,
|
2872
2906
|
jquery=False,
|
2873
2907
|
):
|
2874
|
-
"""Drag
|
2908
|
+
"""Drag-and-drop an element from one selector to another."""
|
2875
2909
|
self.__check_scope()
|
2876
2910
|
if not timeout:
|
2877
2911
|
timeout = settings.SMALL_TIMEOUT
|
@@ -2883,6 +2917,9 @@ class BaseCase(unittest.TestCase):
|
|
2883
2917
|
drop_selector, drop_by = self.__recalculate_selector(
|
2884
2918
|
drop_selector, drop_by
|
2885
2919
|
)
|
2920
|
+
if self.__is_cdp_swap_needed():
|
2921
|
+
self.cdp.gui_drag_and_drop(drag_selector, drop_selector)
|
2922
|
+
return
|
2886
2923
|
drag_element = self.wait_for_element_clickable(
|
2887
2924
|
drag_selector, by=drag_by, timeout=timeout
|
2888
2925
|
)
|
@@ -2918,7 +2955,7 @@ class BaseCase(unittest.TestCase):
|
|
2918
2955
|
def drag_and_drop_with_offset(
|
2919
2956
|
self, selector, x, y, by="css selector", timeout=None
|
2920
2957
|
):
|
2921
|
-
"""Drag
|
2958
|
+
"""Drag-and-drop an element to an {X,Y}-offset location."""
|
2922
2959
|
self.__check_scope()
|
2923
2960
|
if not timeout:
|
2924
2961
|
timeout = settings.SMALL_TIMEOUT
|
@@ -2998,10 +3035,8 @@ class BaseCase(unittest.TestCase):
|
|
2998
3035
|
dropdown_selector, dropdown_by
|
2999
3036
|
)
|
3000
3037
|
pre_action_url = None
|
3001
|
-
|
3038
|
+
with suppress(Exception):
|
3002
3039
|
pre_action_url = self.driver.current_url
|
3003
|
-
except Exception:
|
3004
|
-
pass
|
3005
3040
|
pre_window_count = len(self.driver.window_handles)
|
3006
3041
|
try:
|
3007
3042
|
if option_by == "index":
|
@@ -3105,6 +3140,9 @@ class BaseCase(unittest.TestCase):
|
|
3105
3140
|
timeout = settings.SMALL_TIMEOUT
|
3106
3141
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
3107
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
|
3108
3146
|
self.__select_option(
|
3109
3147
|
dropdown_selector,
|
3110
3148
|
option,
|
@@ -3276,10 +3314,8 @@ class BaseCase(unittest.TestCase):
|
|
3276
3314
|
self.open("data:text/html,<head></head><body><div></div></body>")
|
3277
3315
|
inner_head = """document.getElementsByTagName("head")[0].innerHTML"""
|
3278
3316
|
inner_body = """document.getElementsByTagName("body")[0].innerHTML"""
|
3279
|
-
|
3317
|
+
with suppress(Exception):
|
3280
3318
|
self.wait_for_element_present("body", timeout=1)
|
3281
|
-
except Exception:
|
3282
|
-
pass
|
3283
3319
|
if not found_body:
|
3284
3320
|
self.execute_script('''%s = \"%s\"''' % (inner_body, html_string))
|
3285
3321
|
elif found_body and not found_head:
|
@@ -3353,6 +3389,8 @@ class BaseCase(unittest.TestCase):
|
|
3353
3389
|
|
3354
3390
|
def execute_script(self, script, *args, **kwargs):
|
3355
3391
|
self.__check_scope()
|
3392
|
+
if self.__is_cdp_swap_needed():
|
3393
|
+
return self.cdp.evaluate(script)
|
3356
3394
|
self._check_browser()
|
3357
3395
|
return self.driver.execute_script(script, *args, **kwargs)
|
3358
3396
|
|
@@ -3378,25 +3416,142 @@ class BaseCase(unittest.TestCase):
|
|
3378
3416
|
self.activate_jquery()
|
3379
3417
|
return self.driver.execute_script(script, *args, **kwargs)
|
3380
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
|
+
|
3381
3502
|
def set_window_rect(self, x, y, width, height):
|
3382
3503
|
self.__check_scope()
|
3504
|
+
if self.__is_cdp_swap_needed():
|
3505
|
+
self.cdp.set_window_rect(x, y, width, height)
|
3506
|
+
return
|
3383
3507
|
self._check_browser()
|
3384
3508
|
self.driver.set_window_rect(x, y, width, height)
|
3385
|
-
self.__demo_mode_pause_if_active()
|
3509
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3386
3510
|
|
3387
3511
|
def set_window_size(self, width, height):
|
3388
3512
|
self.__check_scope()
|
3389
3513
|
self._check_browser()
|
3390
3514
|
self.driver.set_window_size(width, height)
|
3391
|
-
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)
|
3392
3522
|
|
3393
3523
|
def maximize_window(self):
|
3394
3524
|
self.__check_scope()
|
3525
|
+
if self.__is_cdp_swap_needed():
|
3526
|
+
self.cdp.maximize()
|
3527
|
+
return
|
3395
3528
|
self._check_browser()
|
3396
3529
|
self.driver.maximize_window()
|
3397
|
-
self.__demo_mode_pause_if_active()
|
3530
|
+
self.__demo_mode_pause_if_active(tiny=True)
|
3398
3531
|
|
3399
|
-
def
|
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)
|
3553
|
+
|
3554
|
+
def switch_to_frame(self, frame="iframe", timeout=None):
|
3400
3555
|
"""Wait for an iframe to appear, and switch to it. This should be
|
3401
3556
|
usable as a drop-in replacement for driver.switch_to.frame().
|
3402
3557
|
The iframe identifier can be a selector, an index, an id, a name,
|
@@ -3723,7 +3878,11 @@ class BaseCase(unittest.TestCase):
|
|
3723
3878
|
"""Opens a new browser tab/window and switches to it by default."""
|
3724
3879
|
self.wait_for_ready_state_complete()
|
3725
3880
|
if switch_to:
|
3726
|
-
|
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()
|
3727
3886
|
else:
|
3728
3887
|
self.driver.execute_script("window.open('');")
|
3729
3888
|
time.sleep(0.01)
|
@@ -3764,6 +3923,7 @@ class BaseCase(unittest.TestCase):
|
|
3764
3923
|
cap_file=None,
|
3765
3924
|
cap_string=None,
|
3766
3925
|
recorder_ext=None,
|
3926
|
+
disable_cookies=None,
|
3767
3927
|
disable_js=None,
|
3768
3928
|
disable_csp=None,
|
3769
3929
|
enable_ws=None,
|
@@ -3775,6 +3935,7 @@ class BaseCase(unittest.TestCase):
|
|
3775
3935
|
log_cdp_events=None,
|
3776
3936
|
no_sandbox=None,
|
3777
3937
|
disable_gpu=None,
|
3938
|
+
headless1=None,
|
3778
3939
|
headless2=None,
|
3779
3940
|
incognito=None,
|
3780
3941
|
guest_mode=None,
|
@@ -3823,6 +3984,7 @@ class BaseCase(unittest.TestCase):
|
|
3823
3984
|
cap_file - the file containing desired capabilities for the browser
|
3824
3985
|
cap_string - the string with desired capabilities for the browser
|
3825
3986
|
recorder_ext - the option to enable the SBase Recorder extension
|
3987
|
+
disable_cookies - the option to disable Cookies (May break things!)
|
3826
3988
|
disable_js - the option to disable JavaScript (May break websites!)
|
3827
3989
|
disable_csp - an option to disable Chrome's Content Security Policy
|
3828
3990
|
enable_ws - the option to enable the Web Security feature (Chrome)
|
@@ -3834,6 +3996,7 @@ class BaseCase(unittest.TestCase):
|
|
3834
3996
|
log_cdp_events - capture {"performance": "ALL", "browser": "ALL"})
|
3835
3997
|
no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)
|
3836
3998
|
disable_gpu - the option to enable Chrome's "Disable GPU" feature
|
3999
|
+
headless1 - the option to use the older headless mode (Chromium)
|
3837
4000
|
headless2 - the option to use the newer headless mode (Chromium)
|
3838
4001
|
incognito - the option to enable Chrome's Incognito mode (Chrome)
|
3839
4002
|
guest_mode - the option to enable Chrome's Guest mode (Chrome)
|
@@ -3920,6 +4083,8 @@ class BaseCase(unittest.TestCase):
|
|
3920
4083
|
user_agent = self.user_agent
|
3921
4084
|
if recorder_ext is None:
|
3922
4085
|
recorder_ext = self.recorder_ext
|
4086
|
+
if disable_cookies is None:
|
4087
|
+
disable_cookies = self.disable_cookies
|
3923
4088
|
if disable_js is None:
|
3924
4089
|
disable_js = self.disable_js
|
3925
4090
|
if disable_csp is None:
|
@@ -3942,6 +4107,8 @@ class BaseCase(unittest.TestCase):
|
|
3942
4107
|
no_sandbox = self.no_sandbox
|
3943
4108
|
if disable_gpu is None:
|
3944
4109
|
disable_gpu = self.disable_gpu
|
4110
|
+
if headless1 is None:
|
4111
|
+
headless1 = self.headless1
|
3945
4112
|
if headless2 is None:
|
3946
4113
|
headless2 = self.headless2
|
3947
4114
|
if incognito is None:
|
@@ -4013,8 +4180,6 @@ class BaseCase(unittest.TestCase):
|
|
4013
4180
|
"Valid options = {%s}" % (browser, valid_browsers)
|
4014
4181
|
)
|
4015
4182
|
# Launch a web browser
|
4016
|
-
from seleniumbase.core import browser_launcher
|
4017
|
-
|
4018
4183
|
new_driver = browser_launcher.get_driver(
|
4019
4184
|
browser_name=browser_name,
|
4020
4185
|
headless=headless,
|
@@ -4031,6 +4196,7 @@ class BaseCase(unittest.TestCase):
|
|
4031
4196
|
cap_file=cap_file,
|
4032
4197
|
cap_string=cap_string,
|
4033
4198
|
recorder_ext=recorder_ext,
|
4199
|
+
disable_cookies=disable_cookies,
|
4034
4200
|
disable_js=disable_js,
|
4035
4201
|
disable_csp=disable_csp,
|
4036
4202
|
enable_ws=enable_ws,
|
@@ -4042,6 +4208,7 @@ class BaseCase(unittest.TestCase):
|
|
4042
4208
|
log_cdp_events=log_cdp_events,
|
4043
4209
|
no_sandbox=no_sandbox,
|
4044
4210
|
disable_gpu=disable_gpu,
|
4211
|
+
headless1=headless1,
|
4045
4212
|
headless2=headless2,
|
4046
4213
|
incognito=incognito,
|
4047
4214
|
guest_mode=guest_mode,
|
@@ -4110,7 +4277,8 @@ class BaseCase(unittest.TestCase):
|
|
4110
4277
|
self.driver.maximize_window()
|
4111
4278
|
self.wait_for_ready_state_complete()
|
4112
4279
|
else:
|
4113
|
-
|
4280
|
+
with suppress(Exception):
|
4281
|
+
self.driver.set_window_size(width, height)
|
4114
4282
|
except Exception:
|
4115
4283
|
pass # Keep existing browser resolution
|
4116
4284
|
elif self.browser == "safari":
|
@@ -4121,10 +4289,8 @@ class BaseCase(unittest.TestCase):
|
|
4121
4289
|
except Exception:
|
4122
4290
|
pass # Keep existing browser resolution
|
4123
4291
|
else:
|
4124
|
-
|
4125
|
-
self.driver.set_window_rect(10,
|
4126
|
-
except Exception:
|
4127
|
-
pass
|
4292
|
+
with suppress(Exception):
|
4293
|
+
self.driver.set_window_rect(10, 46, width, height)
|
4128
4294
|
if self.start_page and len(self.start_page) >= 4:
|
4129
4295
|
if page_utils.is_valid_url(self.start_page):
|
4130
4296
|
self.open(self.start_page)
|
@@ -4134,6 +4300,51 @@ class BaseCase(unittest.TestCase):
|
|
4134
4300
|
self.__dont_record_open = True
|
4135
4301
|
self.open(new_start_page)
|
4136
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
|
4137
4348
|
return new_driver
|
4138
4349
|
|
4139
4350
|
def switch_to_driver(self, driver):
|
@@ -4163,6 +4374,9 @@ class BaseCase(unittest.TestCase):
|
|
4163
4374
|
If a provided selector is not found, then takes a full-page screenshot.
|
4164
4375
|
If the folder provided doesn't exist, it will get created.
|
4165
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
|
4166
4380
|
self.wait_for_ready_state_complete()
|
4167
4381
|
if selector and by:
|
4168
4382
|
selector, by = self.__recalculate_selector(selector, by)
|
@@ -4278,7 +4492,8 @@ class BaseCase(unittest.TestCase):
|
|
4278
4492
|
@Params
|
4279
4493
|
name - The file name to save the current page's HTML to.
|
4280
4494
|
folder - The folder to save the file to. (Default = current folder)"""
|
4281
|
-
self.
|
4495
|
+
if not self.__is_cdp_swap_needed():
|
4496
|
+
self.wait_for_ready_state_complete()
|
4282
4497
|
return page_actions.save_page_source(self.driver, name, folder)
|
4283
4498
|
|
4284
4499
|
def save_cookies(self, name="cookies.txt"):
|
@@ -4306,35 +4521,39 @@ class BaseCase(unittest.TestCase):
|
|
4306
4521
|
cookies_file.writelines(json_cookies)
|
4307
4522
|
cookies_file.close()
|
4308
4523
|
|
4309
|
-
def load_cookies(self, name="cookies.txt"):
|
4310
|
-
"""
|
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)
|
4311
4534
|
self.wait_for_ready_state_complete()
|
4312
|
-
|
4313
|
-
|
4314
|
-
if "/" in name:
|
4315
|
-
name = name.split("/")[-1]
|
4316
|
-
if "\\" in name:
|
4317
|
-
name = name.split("\\")[-1]
|
4318
|
-
if len(name) < 1:
|
4319
|
-
raise Exception("Filename for Cookies is too short!")
|
4320
|
-
if not name.endswith(".txt"):
|
4321
|
-
name = name + ".txt"
|
4322
|
-
folder = constants.SavedCookies.STORAGE_FOLDER
|
4323
|
-
abs_path = os.path.abspath(".")
|
4324
|
-
file_path = os.path.join(abs_path, folder)
|
4325
|
-
cookies_file_path = os.path.join(file_path, name)
|
4326
|
-
json_cookies = None
|
4327
|
-
with open(cookies_file_path, "r") as f:
|
4328
|
-
json_cookies = f.read().strip()
|
4329
|
-
cookies = json.loads(json_cookies)
|
4535
|
+
origin = self.get_origin()
|
4536
|
+
trim_origin = origin.split("://")[-1]
|
4330
4537
|
for cookie in cookies:
|
4331
|
-
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):
|
4332
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
|
4333
4549
|
self.driver.add_cookie(cookie)
|
4334
4550
|
|
4335
4551
|
def delete_all_cookies(self):
|
4336
4552
|
"""Deletes all cookies in the web browser.
|
4337
4553
|
Does NOT delete the saved cookies file."""
|
4554
|
+
if self.__is_cdp_swap_needed():
|
4555
|
+
self.cdp.clear_cookies()
|
4556
|
+
return
|
4338
4557
|
self.wait_for_ready_state_complete()
|
4339
4558
|
self.driver.delete_all_cookies()
|
4340
4559
|
if self.recorder_mode:
|
@@ -4346,7 +4565,6 @@ class BaseCase(unittest.TestCase):
|
|
4346
4565
|
def delete_saved_cookies(self, name="cookies.txt"):
|
4347
4566
|
"""Deletes the cookies file from the "saved_cookies" folder.
|
4348
4567
|
Does NOT delete the cookies from the web browser."""
|
4349
|
-
self.wait_for_ready_state_complete()
|
4350
4568
|
if name.endswith("/"):
|
4351
4569
|
raise Exception("Invalid filename for Cookies!")
|
4352
4570
|
if "/" in name:
|
@@ -4363,11 +4581,129 @@ class BaseCase(unittest.TestCase):
|
|
4363
4581
|
if cookies_file_path.endswith(".txt"):
|
4364
4582
|
os.remove(cookies_file_path)
|
4365
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
|
+
|
4366
4701
|
def wait_for_ready_state_complete(self, timeout=None):
|
4367
4702
|
"""Waits for the "readyState" of the page to be "complete".
|
4368
4703
|
Returns True when the method completes."""
|
4369
4704
|
self.__check_scope()
|
4370
4705
|
self._check_browser()
|
4706
|
+
self.__skip_if_esc()
|
4371
4707
|
if not timeout:
|
4372
4708
|
timeout = settings.EXTREME_TIMEOUT
|
4373
4709
|
if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:
|
@@ -4386,6 +4722,7 @@ class BaseCase(unittest.TestCase):
|
|
4386
4722
|
time.sleep(0.01)
|
4387
4723
|
if self.undetectable:
|
4388
4724
|
time.sleep(0.035)
|
4725
|
+
self.__set_esc_skip()
|
4389
4726
|
return True
|
4390
4727
|
|
4391
4728
|
def wait_for_angularjs(self, timeout=None, **kwargs):
|
@@ -4473,24 +4810,35 @@ class BaseCase(unittest.TestCase):
|
|
4473
4810
|
script = """document.designMode = 'on';"""
|
4474
4811
|
self.execute_script(script)
|
4475
4812
|
|
4476
|
-
def deactivate_design_mode(self):
|
4813
|
+
def deactivate_design_mode(self, url=None):
|
4477
4814
|
# Deactivate Chrome's Design Mode.
|
4478
4815
|
self.wait_for_ready_state_complete()
|
4479
4816
|
script = """document.designMode = 'off';"""
|
4480
4817
|
self.execute_script(script)
|
4481
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
|
+
|
4482
4827
|
def activate_recorder(self):
|
4483
4828
|
from seleniumbase.js_code.recorder_js import recorder_js
|
4484
4829
|
|
4485
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
|
4486
4836
|
raise Exception(
|
4487
|
-
"The Recorder is
|
4837
|
+
"The %s Recorder is for Chromium only!\n"
|
4838
|
+
" (Supported browsers: Chrome and Edge)" % sc
|
4488
4839
|
)
|
4489
4840
|
url = self.driver.current_url
|
4490
|
-
if (
|
4491
|
-
url.startswith("data:") or url.startswith("about:")
|
4492
|
-
or url.startswith("chrome:") or url.startswith("edge:")
|
4493
|
-
):
|
4841
|
+
if url.startswith(("data:", "about:", "chrome:", "edge:")):
|
4494
4842
|
message = (
|
4495
4843
|
"The URL in Recorder-Mode cannot start with: "
|
4496
4844
|
'"data:", "about:", "chrome:", or "edge:"!'
|
@@ -4499,7 +4847,7 @@ class BaseCase(unittest.TestCase):
|
|
4499
4847
|
return
|
4500
4848
|
if self.recorder_ext:
|
4501
4849
|
return # The Recorder extension is already active
|
4502
|
-
|
4850
|
+
with suppress(Exception):
|
4503
4851
|
recorder_on = self.get_session_storage_item("recorder_activated")
|
4504
4852
|
if not recorder_on == "yes":
|
4505
4853
|
self.execute_script(recorder_js)
|
@@ -4508,8 +4856,6 @@ class BaseCase(unittest.TestCase):
|
|
4508
4856
|
print("\n" + message)
|
4509
4857
|
p_msg = "Recorder Mode ACTIVE.<br>[ESC]: Pause. [~`]: Resume."
|
4510
4858
|
self.post_message(p_msg, pause=False, style="error")
|
4511
|
-
except Exception:
|
4512
|
-
pass
|
4513
4859
|
|
4514
4860
|
def __current_url_is_recordable(self):
|
4515
4861
|
url = self.get_current_url()
|
@@ -4549,10 +4895,7 @@ class BaseCase(unittest.TestCase):
|
|
4549
4895
|
|
4550
4896
|
def __get_recorded_actions_on_active_tab(self):
|
4551
4897
|
url = self.driver.current_url
|
4552
|
-
if (
|
4553
|
-
url.startswith("data:") or url.startswith("about:")
|
4554
|
-
or url.startswith("chrome:") or url.startswith("edge:")
|
4555
|
-
):
|
4898
|
+
if url.startswith(("data:", "about:", "chrome:", "edge:")):
|
4556
4899
|
return []
|
4557
4900
|
self.__origins_to_save.append(self.get_origin())
|
4558
4901
|
actions = self.get_session_storage_item("recorded_actions")
|
@@ -4563,9 +4906,9 @@ class BaseCase(unittest.TestCase):
|
|
4563
4906
|
return []
|
4564
4907
|
|
4565
4908
|
def __process_recorded_actions(self):
|
4909
|
+
"""Generates code after the SeleniumBase Recorder runs."""
|
4566
4910
|
if self.driver is None:
|
4567
4911
|
return
|
4568
|
-
import colorama
|
4569
4912
|
from seleniumbase.core import recorder_helper
|
4570
4913
|
|
4571
4914
|
raw_actions = [] # All raw actions from sessionStorage
|
@@ -4767,10 +5110,7 @@ class BaseCase(unittest.TestCase):
|
|
4767
5110
|
or srt_actions[n - 1][0] == "jq_cl"
|
4768
5111
|
or srt_actions[n - 1][0] == "jq_ca"
|
4769
5112
|
):
|
4770
|
-
if (
|
4771
|
-
srt_actions[n - 1][1].startswith("input")
|
4772
|
-
or srt_actions[n - 1][1].startswith("button")
|
4773
|
-
):
|
5113
|
+
if srt_actions[n - 1][1].startswith(("input", "button")):
|
4774
5114
|
srt_actions[n][0] = "f_url"
|
4775
5115
|
elif srt_actions[n - 1][0] == "input":
|
4776
5116
|
if srt_actions[n - 1][2].endswith("\n"):
|
@@ -5118,7 +5458,6 @@ class BaseCase(unittest.TestCase):
|
|
5118
5458
|
and (filename == "base_case.py" or methodname == "runTest")
|
5119
5459
|
):
|
5120
5460
|
import traceback
|
5121
|
-
|
5122
5461
|
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
5123
5462
|
test_base = stack_base.split(", in ")[0]
|
5124
5463
|
if hasattr(self, "cm_filename") and self.cm_filename:
|
@@ -5166,7 +5505,10 @@ class BaseCase(unittest.TestCase):
|
|
5166
5505
|
new_file = True
|
5167
5506
|
sb_config._recorded_actions[filename] = []
|
5168
5507
|
data.append("from seleniumbase import BaseCase")
|
5169
|
-
|
5508
|
+
if "--uc" in sys.argv:
|
5509
|
+
data.append('BaseCase.main(__name__, __file__, "--uc")')
|
5510
|
+
else:
|
5511
|
+
data.append("BaseCase.main(__name__, __file__)")
|
5170
5512
|
data.append("")
|
5171
5513
|
data.append("")
|
5172
5514
|
data.append("class %s(BaseCase):" % classname)
|
@@ -5176,7 +5518,13 @@ class BaseCase(unittest.TestCase):
|
|
5176
5518
|
data.append("class %s(BaseCase):" % classname)
|
5177
5519
|
data.append(" def %s(self):" % methodname)
|
5178
5520
|
if len(sb_actions) > 0:
|
5521
|
+
if "--uc" in sys.argv:
|
5522
|
+
data.append(" self.activate_cdp_mode()")
|
5179
5523
|
for action in sb_actions:
|
5524
|
+
if "--uc" in sys.argv:
|
5525
|
+
action = action.replace(
|
5526
|
+
"self.type(", "self.press_keys("
|
5527
|
+
)
|
5180
5528
|
data.append(" " + action)
|
5181
5529
|
else:
|
5182
5530
|
data.append(" pass")
|
@@ -5188,11 +5536,9 @@ class BaseCase(unittest.TestCase):
|
|
5188
5536
|
if recordings_folder.endswith("/"):
|
5189
5537
|
recordings_folder = recordings_folder[:-1]
|
5190
5538
|
if not os.path.exists(recordings_folder):
|
5191
|
-
|
5539
|
+
with suppress(Exception):
|
5192
5540
|
os.makedirs(recordings_folder)
|
5193
5541
|
sys.stdout.write("\nCreated recordings%s" % os.sep)
|
5194
|
-
except Exception:
|
5195
|
-
pass
|
5196
5542
|
|
5197
5543
|
data = []
|
5198
5544
|
data.append("")
|
@@ -5293,12 +5639,10 @@ class BaseCase(unittest.TestCase):
|
|
5293
5639
|
if not new_file:
|
5294
5640
|
rec_message = ">>> RECORDING ADDED to: "
|
5295
5641
|
star_len = len(rec_message) + len(file_path)
|
5296
|
-
|
5642
|
+
with suppress(Exception):
|
5297
5643
|
terminal_size = os.get_terminal_size().columns
|
5298
5644
|
if terminal_size > 30 and star_len > terminal_size:
|
5299
5645
|
star_len = terminal_size
|
5300
|
-
except Exception:
|
5301
|
-
pass
|
5302
5646
|
spc = "\n\n"
|
5303
5647
|
if hasattr(self, "rec_print") and self.rec_print:
|
5304
5648
|
spc = ""
|
@@ -5358,6 +5702,9 @@ class BaseCase(unittest.TestCase):
|
|
5358
5702
|
data.append(" Scenario: %s" % scenario_test)
|
5359
5703
|
if len(behave_actions) > 0:
|
5360
5704
|
count = 0
|
5705
|
+
if "--uc" in sys.argv:
|
5706
|
+
data.append(" Given Activate CDP Mode")
|
5707
|
+
count += 1
|
5361
5708
|
for action in behave_actions:
|
5362
5709
|
if count == 0:
|
5363
5710
|
data.append(" Given " + action)
|
@@ -5371,22 +5718,16 @@ class BaseCase(unittest.TestCase):
|
|
5371
5718
|
if recordings_folder.endswith("/"):
|
5372
5719
|
recordings_folder = recordings_folder[:-1]
|
5373
5720
|
if not os.path.exists(recordings_folder):
|
5374
|
-
|
5721
|
+
with suppress(Exception):
|
5375
5722
|
os.makedirs(recordings_folder)
|
5376
|
-
except Exception:
|
5377
|
-
pass
|
5378
5723
|
features_folder = os.path.join(recordings_folder, "features")
|
5379
5724
|
if not os.path.exists(features_folder):
|
5380
|
-
|
5725
|
+
with suppress(Exception):
|
5381
5726
|
os.makedirs(features_folder)
|
5382
|
-
except Exception:
|
5383
|
-
pass
|
5384
5727
|
steps_folder = os.path.join(features_folder, "steps")
|
5385
5728
|
if not os.path.exists(steps_folder):
|
5386
|
-
|
5729
|
+
with suppress(Exception):
|
5387
5730
|
os.makedirs(steps_folder)
|
5388
|
-
except Exception:
|
5389
|
-
pass
|
5390
5731
|
|
5391
5732
|
file_name = filename.split(".")[0]
|
5392
5733
|
if hasattr(self, "is_behave") and self.is_behave:
|
@@ -5401,12 +5742,10 @@ class BaseCase(unittest.TestCase):
|
|
5401
5742
|
if not new_file:
|
5402
5743
|
rec_message = ">>> RECORDING ADDED to: "
|
5403
5744
|
star_len = len(rec_message) + len(file_path)
|
5404
|
-
|
5745
|
+
with suppress(Exception):
|
5405
5746
|
terminal_size = os.get_terminal_size().columns
|
5406
5747
|
if terminal_size > 30 and star_len > terminal_size:
|
5407
5748
|
star_len = terminal_size
|
5408
|
-
except Exception:
|
5409
|
-
pass
|
5410
5749
|
spc = "\n"
|
5411
5750
|
if hasattr(self, "rec_print") and self.rec_print:
|
5412
5751
|
spc = ""
|
@@ -5512,16 +5851,17 @@ class BaseCase(unittest.TestCase):
|
|
5512
5851
|
print("Created recordings/features/steps/imported.py")
|
5513
5852
|
|
5514
5853
|
def bring_active_window_to_front(self):
|
5515
|
-
"""Brings the active browser window to the front.
|
5516
|
-
|
5854
|
+
"""Brings the active browser window to the front (on top).
|
5855
|
+
Useful when multiple drivers are being used at the same time."""
|
5517
5856
|
self.__check_scope()
|
5518
|
-
|
5857
|
+
if self.__is_cdp_swap_needed():
|
5858
|
+
self.cdp.bring_active_window_to_front()
|
5859
|
+
return
|
5860
|
+
with suppress(Exception):
|
5519
5861
|
if not self.__is_in_frame():
|
5520
5862
|
# Only bring the window to the front if not in a frame
|
5521
5863
|
# because the driver resets itself to default content.
|
5522
5864
|
self.switch_to_window(self.driver.current_window_handle)
|
5523
|
-
except Exception:
|
5524
|
-
pass
|
5525
5865
|
|
5526
5866
|
def bring_to_front(self, selector, by="css selector"):
|
5527
5867
|
"""Updates the Z-index of a page element to bring it into view.
|
@@ -5551,7 +5891,7 @@ class BaseCase(unittest.TestCase):
|
|
5551
5891
|
def highlight_click(
|
5552
5892
|
self, selector, by="css selector", loops=3, scroll=True, timeout=None,
|
5553
5893
|
):
|
5554
|
-
"""Highlights the element and then clicks it."""
|
5894
|
+
"""Highlights the element, and then clicks it."""
|
5555
5895
|
self.__check_scope()
|
5556
5896
|
if not timeout:
|
5557
5897
|
timeout = settings.SMALL_TIMEOUT
|
@@ -5605,11 +5945,43 @@ class BaseCase(unittest.TestCase):
|
|
5605
5945
|
if self.is_element_visible(selector, by=by):
|
5606
5946
|
self.__highlight(selector, by=by, loops=loops, scroll=scroll)
|
5607
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
|
+
|
5608
5980
|
def __highlight(
|
5609
5981
|
self, selector, by="css selector", loops=None, scroll=True
|
5610
5982
|
):
|
5611
5983
|
"""This method uses fancy JavaScript to highlight an element.
|
5612
|
-
(
|
5984
|
+
(Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)"""
|
5613
5985
|
self.__check_scope()
|
5614
5986
|
selector, by = self.__recalculate_selector(selector, by, xp_ok=False)
|
5615
5987
|
element = self.wait_for_element_visible(
|
@@ -5693,13 +6065,19 @@ class BaseCase(unittest.TestCase):
|
|
5693
6065
|
):
|
5694
6066
|
"""This method uses fancy JavaScript to highlight an element.
|
5695
6067
|
@Params
|
5696
|
-
selector - the selector of the element to find
|
6068
|
+
selector - the selector of the element to find (Accepts WebElement)
|
5697
6069
|
by - the type of selector to search by (Default: CSS)
|
5698
6070
|
loops - # of times to repeat the highlight animation
|
5699
6071
|
(Default: 4. Each loop lasts for about 0.2s)
|
5700
6072
|
scroll - the option to scroll to the element first (Default: True)
|
5701
6073
|
timeout - the time to wait for the element to appear """
|
5702
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
|
5703
6081
|
if not timeout:
|
5704
6082
|
timeout = settings.SMALL_TIMEOUT
|
5705
6083
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
@@ -5711,7 +6089,30 @@ class BaseCase(unittest.TestCase):
|
|
5711
6089
|
action = ["hi_li", selector, origin, time_stamp]
|
5712
6090
|
self.__extra_actions.append(action)
|
5713
6091
|
|
5714
|
-
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"):
|
5715
6116
|
"""Simulates pressing the UP Arrow on the keyboard.
|
5716
6117
|
By default, "html" will be used as the CSS Selector target.
|
5717
6118
|
You can specify how many times in-a-row the action happens."""
|
@@ -5733,7 +6134,7 @@ class BaseCase(unittest.TestCase):
|
|
5733
6134
|
if self.slow_mode:
|
5734
6135
|
time.sleep(0.1)
|
5735
6136
|
|
5736
|
-
def press_down_arrow(self, selector="
|
6137
|
+
def press_down_arrow(self, selector="body", times=1, by="css selector"):
|
5737
6138
|
"""Simulates pressing the DOWN Arrow on the keyboard.
|
5738
6139
|
By default, "html" will be used as the CSS Selector target.
|
5739
6140
|
You can specify how many times in-a-row the action happens."""
|
@@ -5755,7 +6156,7 @@ class BaseCase(unittest.TestCase):
|
|
5755
6156
|
if self.slow_mode:
|
5756
6157
|
time.sleep(0.1)
|
5757
6158
|
|
5758
|
-
def press_left_arrow(self, selector="
|
6159
|
+
def press_left_arrow(self, selector="body", times=1, by="css selector"):
|
5759
6160
|
"""Simulates pressing the LEFT Arrow on the keyboard.
|
5760
6161
|
By default, "html" will be used as the CSS Selector target.
|
5761
6162
|
You can specify how many times in-a-row the action happens."""
|
@@ -5777,7 +6178,7 @@ class BaseCase(unittest.TestCase):
|
|
5777
6178
|
if self.slow_mode:
|
5778
6179
|
time.sleep(0.1)
|
5779
6180
|
|
5780
|
-
def press_right_arrow(self, selector="
|
6181
|
+
def press_right_arrow(self, selector="body", times=1, by="css selector"):
|
5781
6182
|
"""Simulates pressing the RIGHT Arrow on the keyboard.
|
5782
6183
|
By default, "html" will be used as the CSS Selector target.
|
5783
6184
|
You can specify how many times in-a-row the action happens."""
|
@@ -5806,6 +6207,9 @@ class BaseCase(unittest.TestCase):
|
|
5806
6207
|
timeout = settings.SMALL_TIMEOUT
|
5807
6208
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
5808
6209
|
timeout = self.__get_new_timeout(timeout)
|
6210
|
+
if self.__is_cdp_swap_needed():
|
6211
|
+
self.cdp.scroll_into_view(selector)
|
6212
|
+
return
|
5809
6213
|
if self.demo_mode or self.slow_mode:
|
5810
6214
|
self.slow_scroll_to(selector, by=by, timeout=timeout)
|
5811
6215
|
return
|
@@ -5836,6 +6240,9 @@ class BaseCase(unittest.TestCase):
|
|
5836
6240
|
original_selector = selector
|
5837
6241
|
original_by = by
|
5838
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
|
5839
6246
|
element = self.wait_for_element_visible(
|
5840
6247
|
original_selector, by=original_by, timeout=timeout
|
5841
6248
|
)
|
@@ -5873,30 +6280,45 @@ class BaseCase(unittest.TestCase):
|
|
5873
6280
|
timeout = settings.SMALL_TIMEOUT
|
5874
6281
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
5875
6282
|
timeout = self.__get_new_timeout(timeout)
|
6283
|
+
if self.__is_cdp_swap_needed():
|
6284
|
+
self.cdp.scroll_into_view(selector)
|
6285
|
+
return
|
5876
6286
|
element = self.wait_for_element_visible(selector, by, timeout=timeout)
|
5877
6287
|
self.execute_script("arguments[0].scrollIntoView();", element)
|
5878
6288
|
|
5879
6289
|
def scroll_to_top(self):
|
5880
6290
|
"""Scroll to the top of the page."""
|
5881
6291
|
self.__check_scope()
|
6292
|
+
if self.__is_cdp_swap_needed():
|
6293
|
+
self.cdp.scroll_to_top()
|
6294
|
+
return
|
5882
6295
|
scroll_script = "window.scrollTo(0, 0);"
|
5883
|
-
|
6296
|
+
with suppress(Exception):
|
5884
6297
|
self.execute_script(scroll_script)
|
5885
6298
|
time.sleep(0.012)
|
5886
|
-
return True
|
5887
|
-
except Exception:
|
5888
|
-
return False
|
5889
6299
|
|
5890
6300
|
def scroll_to_bottom(self):
|
5891
6301
|
"""Scroll to the bottom of the page."""
|
5892
6302
|
self.__check_scope()
|
6303
|
+
if self.__is_cdp_swap_needed():
|
6304
|
+
self.cdp.scroll_to_bottom()
|
6305
|
+
return
|
5893
6306
|
scroll_script = "window.scrollTo(0, 10000);"
|
5894
|
-
|
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):
|
5895
6320
|
self.execute_script(scroll_script)
|
5896
6321
|
time.sleep(0.012)
|
5897
|
-
return True
|
5898
|
-
except Exception:
|
5899
|
-
return False
|
5900
6322
|
|
5901
6323
|
def click_xpath(self, xpath):
|
5902
6324
|
"""Technically, self.click() automatically detects xpath selectors,
|
@@ -5915,6 +6337,9 @@ class BaseCase(unittest.TestCase):
|
|
5915
6337
|
Can be used to click hidden / invisible elements.
|
5916
6338
|
If "all_matches" is False, only the first match is clicked.
|
5917
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
|
5918
6343
|
self.wait_for_ready_state_complete()
|
5919
6344
|
if not timeout or timeout is True:
|
5920
6345
|
timeout = settings.SMALL_TIMEOUT
|
@@ -5954,10 +6379,8 @@ class BaseCase(unittest.TestCase):
|
|
5954
6379
|
time_stamp = 0
|
5955
6380
|
action = ["", "", "", time_stamp]
|
5956
6381
|
pre_action_url = None
|
5957
|
-
|
6382
|
+
with suppress(Exception):
|
5958
6383
|
pre_action_url = self.driver.current_url
|
5959
|
-
except Exception:
|
5960
|
-
pass
|
5961
6384
|
pre_window_count = len(self.driver.window_handles)
|
5962
6385
|
if self.recorder_mode and not self.__dont_record_js_click:
|
5963
6386
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6059,10 +6482,8 @@ class BaseCase(unittest.TestCase):
|
|
6059
6482
|
# If a click closes the active window,
|
6060
6483
|
# switch to the last one if it exists.
|
6061
6484
|
self.switch_to_window(-1)
|
6062
|
-
|
6485
|
+
with suppress(Exception):
|
6063
6486
|
self.wait_for_ready_state_complete()
|
6064
|
-
except Exception:
|
6065
|
-
pass
|
6066
6487
|
self.__demo_mode_pause_if_active()
|
6067
6488
|
|
6068
6489
|
def js_click_if_present(self, selector, by="css selector", timeout=0):
|
@@ -6074,10 +6495,8 @@ class BaseCase(unittest.TestCase):
|
|
6074
6495
|
if self.is_element_present(selector, by=by):
|
6075
6496
|
self.js_click(selector, by=by)
|
6076
6497
|
elif timeout > 0:
|
6077
|
-
|
6498
|
+
with suppress(Exception):
|
6078
6499
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
6079
|
-
except Exception:
|
6080
|
-
pass
|
6081
6500
|
if self.is_element_present(selector, by=by):
|
6082
6501
|
self.js_click(selector, by=by)
|
6083
6502
|
|
@@ -6090,10 +6509,8 @@ class BaseCase(unittest.TestCase):
|
|
6090
6509
|
if self.is_element_visible(selector, by=by):
|
6091
6510
|
self.js_click(selector, by=by)
|
6092
6511
|
elif timeout > 0:
|
6093
|
-
|
6512
|
+
with suppress(Exception):
|
6094
6513
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
6095
|
-
except Exception:
|
6096
|
-
pass
|
6097
6514
|
if self.is_element_visible(selector, by=by):
|
6098
6515
|
self.js_click(selector, by=by)
|
6099
6516
|
|
@@ -6186,13 +6603,11 @@ class BaseCase(unittest.TestCase):
|
|
6186
6603
|
"""Hide the first element on the page that matches the selector."""
|
6187
6604
|
self.__check_scope()
|
6188
6605
|
element = None
|
6189
|
-
|
6606
|
+
with suppress(Exception):
|
6190
6607
|
self.wait_for_element_visible("body", timeout=1.5)
|
6191
6608
|
element = self.wait_for_element_present(
|
6192
6609
|
selector, by=by, timeout=0.5
|
6193
6610
|
)
|
6194
|
-
except Exception:
|
6195
|
-
pass
|
6196
6611
|
selector, by = self.__recalculate_selector(selector, by)
|
6197
6612
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6198
6613
|
if ":contains(" in css_selector and element:
|
@@ -6218,10 +6633,8 @@ class BaseCase(unittest.TestCase):
|
|
6218
6633
|
def hide_elements(self, selector, by="css selector"):
|
6219
6634
|
"""Hide all elements on the page that match the selector."""
|
6220
6635
|
self.__check_scope()
|
6221
|
-
|
6636
|
+
with suppress(Exception):
|
6222
6637
|
self.wait_for_element_visible("body", timeout=1.5)
|
6223
|
-
except Exception:
|
6224
|
-
pass
|
6225
6638
|
selector, by = self.__recalculate_selector(selector, by)
|
6226
6639
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6227
6640
|
if ":contains(" in css_selector:
|
@@ -6244,11 +6657,9 @@ class BaseCase(unittest.TestCase):
|
|
6244
6657
|
"""Show the first element on the page that matches the selector."""
|
6245
6658
|
self.__check_scope()
|
6246
6659
|
element = None
|
6247
|
-
|
6660
|
+
with suppress(Exception):
|
6248
6661
|
self.wait_for_element_visible("body", timeout=1.5)
|
6249
6662
|
element = self.wait_for_element_present(selector, by=by, timeout=1)
|
6250
|
-
except Exception:
|
6251
|
-
pass
|
6252
6663
|
selector, by = self.__recalculate_selector(selector, by)
|
6253
6664
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6254
6665
|
if ":contains(" in css_selector and element:
|
@@ -6274,10 +6685,8 @@ class BaseCase(unittest.TestCase):
|
|
6274
6685
|
def show_elements(self, selector, by="css selector"):
|
6275
6686
|
"""Show all elements on the page that match the selector."""
|
6276
6687
|
self.__check_scope()
|
6277
|
-
|
6688
|
+
with suppress(Exception):
|
6278
6689
|
self.wait_for_element_visible("body", timeout=1.5)
|
6279
|
-
except Exception:
|
6280
|
-
pass
|
6281
6690
|
selector, by = self.__recalculate_selector(selector, by)
|
6282
6691
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6283
6692
|
if ":contains(" in css_selector:
|
@@ -6299,14 +6708,15 @@ class BaseCase(unittest.TestCase):
|
|
6299
6708
|
def remove_element(self, selector, by="css selector"):
|
6300
6709
|
"""Remove the first element on the page that matches the selector."""
|
6301
6710
|
self.__check_scope()
|
6711
|
+
if self.__is_cdp_swap_needed():
|
6712
|
+
self.cdp.remove_element(selector)
|
6713
|
+
return
|
6302
6714
|
element = None
|
6303
|
-
|
6715
|
+
with suppress(Exception):
|
6304
6716
|
self.wait_for_element_visible("body", timeout=1.5)
|
6305
6717
|
element = self.wait_for_element_present(
|
6306
6718
|
selector, by=by, timeout=0.5
|
6307
6719
|
)
|
6308
|
-
except Exception:
|
6309
|
-
pass
|
6310
6720
|
selector, by = self.__recalculate_selector(selector, by)
|
6311
6721
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6312
6722
|
if ":contains(" in css_selector and element:
|
@@ -6332,10 +6742,11 @@ class BaseCase(unittest.TestCase):
|
|
6332
6742
|
def remove_elements(self, selector, by="css selector"):
|
6333
6743
|
"""Remove all elements on the page that match the selector."""
|
6334
6744
|
self.__check_scope()
|
6335
|
-
|
6745
|
+
if self.__is_cdp_swap_needed():
|
6746
|
+
self.cdp.remove_elements(selector)
|
6747
|
+
return
|
6748
|
+
with suppress(Exception):
|
6336
6749
|
self.wait_for_element_visible("body", timeout=1.5)
|
6337
|
-
except Exception:
|
6338
|
-
pass
|
6339
6750
|
selector, by = self.__recalculate_selector(selector, by)
|
6340
6751
|
css_selector = self.convert_to_css_selector(selector, by=by)
|
6341
6752
|
if ":contains(" in css_selector:
|
@@ -6400,10 +6811,8 @@ class BaseCase(unittest.TestCase):
|
|
6400
6811
|
$elements[index].setAttribute('class', new_class);}"""
|
6401
6812
|
% css_selector
|
6402
6813
|
)
|
6403
|
-
|
6814
|
+
with suppress(Exception):
|
6404
6815
|
self.execute_script(script)
|
6405
|
-
except Exception:
|
6406
|
-
pass
|
6407
6816
|
if self.recorder_mode and self.__current_url_is_recordable():
|
6408
6817
|
if self.get_session_storage_item("pause_recorder") == "no":
|
6409
6818
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6421,10 +6830,8 @@ class BaseCase(unittest.TestCase):
|
|
6421
6830
|
self.is_chromium()
|
6422
6831
|
and self.driver.current_url.startswith("http")
|
6423
6832
|
):
|
6424
|
-
|
6833
|
+
with suppress(Exception):
|
6425
6834
|
self.driver.execute_script("window.onbeforeunload=null;")
|
6426
|
-
except Exception:
|
6427
|
-
pass
|
6428
6835
|
|
6429
6836
|
def get_domain_url(self, url):
|
6430
6837
|
self.__check_scope()
|
@@ -6440,12 +6847,10 @@ class BaseCase(unittest.TestCase):
|
|
6440
6847
|
from bs4 import BeautifulSoup
|
6441
6848
|
|
6442
6849
|
if not source:
|
6443
|
-
|
6850
|
+
with suppress(Exception):
|
6444
6851
|
self.wait_for_element_visible(
|
6445
6852
|
"body", timeout=settings.MINI_TIMEOUT
|
6446
6853
|
)
|
6447
|
-
except Exception:
|
6448
|
-
pass
|
6449
6854
|
source = self.get_page_source()
|
6450
6855
|
return BeautifulSoup(source, "html.parser")
|
6451
6856
|
|
@@ -6458,11 +6863,9 @@ class BaseCase(unittest.TestCase):
|
|
6458
6863
|
time.sleep(0.08)
|
6459
6864
|
if self.undetectable:
|
6460
6865
|
time.sleep(0.02)
|
6461
|
-
|
6866
|
+
with suppress(Exception):
|
6462
6867
|
self.wait_for_element_present("body", timeout=1.5)
|
6463
6868
|
self.wait_for_element_visible("body", timeout=1.5)
|
6464
|
-
except Exception:
|
6465
|
-
pass
|
6466
6869
|
if self.__needs_minimum_wait():
|
6467
6870
|
time.sleep(0.25)
|
6468
6871
|
if self.undetectable:
|
@@ -6524,6 +6927,7 @@ class BaseCase(unittest.TestCase):
|
|
6524
6927
|
for link in all_links:
|
6525
6928
|
if (
|
6526
6929
|
"data:" not in link
|
6930
|
+
and "tel:" not in link
|
6527
6931
|
and "mailto:" not in link
|
6528
6932
|
and "javascript:" not in link
|
6529
6933
|
and "://fonts.gstatic.com" not in link
|
@@ -6657,18 +7061,19 @@ class BaseCase(unittest.TestCase):
|
|
6657
7061
|
constants.PipInstall.FINDLOCK
|
6658
7062
|
)
|
6659
7063
|
with pip_find_lock:
|
6660
|
-
|
6661
|
-
|
6662
|
-
|
6663
|
-
):
|
7064
|
+
with suppress(Exception):
|
7065
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7066
|
+
if sys.version_info < (3, 9):
|
6664
7067
|
# Fix bug in newer cryptography for Python 3.7 and 3.8:
|
6665
7068
|
# "pyo3_runtime.PanicException: Python API call failed"
|
6666
7069
|
try:
|
6667
7070
|
import cryptography
|
6668
7071
|
if cryptography.__version__ != "39.0.2":
|
7072
|
+
del cryptography # To get newer ver
|
6669
7073
|
shared_utils.pip_install(
|
6670
7074
|
"cryptography", version="39.0.2"
|
6671
7075
|
)
|
7076
|
+
import cryptography
|
6672
7077
|
except Exception:
|
6673
7078
|
shared_utils.pip_install(
|
6674
7079
|
"cryptography", version="39.0.2"
|
@@ -6676,12 +7081,7 @@ class BaseCase(unittest.TestCase):
|
|
6676
7081
|
try:
|
6677
7082
|
from pdfminer.high_level import extract_text
|
6678
7083
|
except Exception:
|
6679
|
-
|
6680
|
-
shared_utils.pip_install(
|
6681
|
-
"pdfminer.six", version="20221105"
|
6682
|
-
)
|
6683
|
-
else:
|
6684
|
-
shared_utils.pip_install("pdfminer.six")
|
7084
|
+
shared_utils.pip_install("pdfminer.six")
|
6685
7085
|
from pdfminer.high_level import extract_text
|
6686
7086
|
if not password:
|
6687
7087
|
password = ""
|
@@ -6801,10 +7201,8 @@ class BaseCase(unittest.TestCase):
|
|
6801
7201
|
if len(folder) < 1:
|
6802
7202
|
raise Exception("Minimum folder name length = 1.")
|
6803
7203
|
if not os.path.exists(folder):
|
6804
|
-
|
7204
|
+
with suppress(Exception):
|
6805
7205
|
os.makedirs(folder)
|
6806
|
-
except Exception:
|
6807
|
-
pass
|
6808
7206
|
|
6809
7207
|
def choose_file(
|
6810
7208
|
self, selector, file_path, by="css selector", timeout=None
|
@@ -6844,10 +7242,8 @@ class BaseCase(unittest.TestCase):
|
|
6844
7242
|
self.__scroll_to_element(element, selector, by)
|
6845
7243
|
pre_action_url = None
|
6846
7244
|
if self.demo_mode:
|
6847
|
-
|
7245
|
+
with suppress(Exception):
|
6848
7246
|
pre_action_url = self.driver.current_url
|
6849
|
-
except Exception:
|
6850
|
-
pass
|
6851
7247
|
if self.recorder_mode and self.__current_url_is_recordable():
|
6852
7248
|
if self.get_session_storage_item("pause_recorder") == "no":
|
6853
7249
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -6917,6 +7313,8 @@ class BaseCase(unittest.TestCase):
|
|
6917
7313
|
constants.PipInstall.FINDLOCK
|
6918
7314
|
)
|
6919
7315
|
with pip_find_lock:
|
7316
|
+
with suppress(Exception):
|
7317
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
6920
7318
|
try:
|
6921
7319
|
from PIL import Image, ImageDraw
|
6922
7320
|
except Exception:
|
@@ -6962,6 +7360,10 @@ class BaseCase(unittest.TestCase):
|
|
6962
7360
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
6963
7361
|
)
|
6964
7362
|
with download_file_lock:
|
7363
|
+
with suppress(Exception):
|
7364
|
+
shared_utils.make_writable(
|
7365
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7366
|
+
)
|
6965
7367
|
if not destination_folder:
|
6966
7368
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
6967
7369
|
if not os.path.exists(destination_folder):
|
@@ -6982,6 +7384,10 @@ class BaseCase(unittest.TestCase):
|
|
6982
7384
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
6983
7385
|
)
|
6984
7386
|
with download_file_lock:
|
7387
|
+
with suppress(Exception):
|
7388
|
+
shared_utils.make_writable(
|
7389
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7390
|
+
)
|
6985
7391
|
if not destination_folder:
|
6986
7392
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
6987
7393
|
if not os.path.exists(destination_folder):
|
@@ -7087,6 +7493,8 @@ class BaseCase(unittest.TestCase):
|
|
7087
7493
|
constants.MultiBrowser.FILE_IO_LOCK
|
7088
7494
|
)
|
7089
7495
|
with file_io_lock:
|
7496
|
+
with suppress(Exception):
|
7497
|
+
shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
|
7090
7498
|
with open(fpath, "r") as f:
|
7091
7499
|
data = f.read().strip()
|
7092
7500
|
return data
|
@@ -7135,10 +7543,8 @@ class BaseCase(unittest.TestCase):
|
|
7135
7543
|
Those paths are usually the same. (browser-dependent)."""
|
7136
7544
|
if self.is_downloaded_file_present(file, browser=browser):
|
7137
7545
|
file_path = self.get_path_of_downloaded_file(file, browser=browser)
|
7138
|
-
|
7546
|
+
with suppress(Exception):
|
7139
7547
|
os.remove(file_path)
|
7140
|
-
except Exception:
|
7141
|
-
pass
|
7142
7548
|
|
7143
7549
|
def delete_downloaded_file(self, file, browser=False):
|
7144
7550
|
"""Same as self.delete_downloaded_file_if_present()
|
@@ -7155,10 +7561,8 @@ class BaseCase(unittest.TestCase):
|
|
7155
7561
|
Those paths are usually the same. (browser-dependent)."""
|
7156
7562
|
if self.is_downloaded_file_present(file, browser=browser):
|
7157
7563
|
file_path = self.get_path_of_downloaded_file(file, browser=browser)
|
7158
|
-
|
7564
|
+
with suppress(Exception):
|
7159
7565
|
os.remove(file_path)
|
7160
|
-
except Exception:
|
7161
|
-
pass
|
7162
7566
|
|
7163
7567
|
def assert_downloaded_file(self, file, timeout=None, browser=False):
|
7164
7568
|
"""Asserts that the file exists in SeleniumBase's [Downloads Folder].
|
@@ -7215,13 +7619,11 @@ class BaseCase(unittest.TestCase):
|
|
7215
7619
|
self.__extra_actions.append(action)
|
7216
7620
|
if self.demo_mode:
|
7217
7621
|
messenger_post = "<b>ASSERT DOWNLOADED FILE</b>: [%s]" % file
|
7218
|
-
|
7622
|
+
with suppress(Exception):
|
7219
7623
|
js_utils.activate_jquery(self.driver)
|
7220
7624
|
js_utils.post_messenger_success_message(
|
7221
7625
|
self.driver, messenger_post, self.message_duration
|
7222
7626
|
)
|
7223
|
-
except Exception:
|
7224
|
-
pass
|
7225
7627
|
|
7226
7628
|
def assert_downloaded_file_regex(self, regex, timeout=None, browser=False):
|
7227
7629
|
"""Assert the filename regex exists in SeleniumBase's Downloads Folder.
|
@@ -7270,13 +7672,11 @@ class BaseCase(unittest.TestCase):
|
|
7270
7672
|
messenger_post = (
|
7271
7673
|
"<b>ASSERT DOWNLOADED FILE REGEX</b>: [%s]" % regex
|
7272
7674
|
)
|
7273
|
-
|
7675
|
+
with suppress(Exception):
|
7274
7676
|
js_utils.activate_jquery(self.driver)
|
7275
7677
|
js_utils.post_messenger_success_message(
|
7276
7678
|
self.driver, messenger_post, self.message_duration
|
7277
7679
|
)
|
7278
|
-
except Exception:
|
7279
|
-
pass
|
7280
7680
|
|
7281
7681
|
def assert_data_in_downloaded_file(
|
7282
7682
|
self, data, file, timeout=None, browser=False
|
@@ -7295,37 +7695,37 @@ class BaseCase(unittest.TestCase):
|
|
7295
7695
|
|
7296
7696
|
def assert_true(self, expr, msg=None):
|
7297
7697
|
"""Asserts that the expression is True.
|
7298
|
-
|
7698
|
+
Raises an exception if the statement if False."""
|
7299
7699
|
self.assertTrue(expr, msg=msg)
|
7300
7700
|
|
7301
7701
|
def assert_false(self, expr, msg=None):
|
7302
7702
|
"""Asserts that the expression is False.
|
7303
|
-
|
7703
|
+
Raises an exception if the statement if True."""
|
7304
7704
|
self.assertFalse(expr, msg=msg)
|
7305
7705
|
|
7306
7706
|
def assert_equal(self, first, second, msg=None):
|
7307
7707
|
"""Asserts that the two values are equal.
|
7308
|
-
|
7708
|
+
Raises an exception if the values are not equal."""
|
7309
7709
|
self.assertEqual(first, second, msg=msg)
|
7310
7710
|
|
7311
7711
|
def assert_not_equal(self, first, second, msg=None):
|
7312
7712
|
"""Asserts that the two values are not equal.
|
7313
|
-
|
7713
|
+
Raises an exception if the values are equal."""
|
7314
7714
|
self.assertNotEqual(first, second, msg=msg)
|
7315
7715
|
|
7316
7716
|
def assert_in(self, first, second, msg=None):
|
7317
7717
|
"""Asserts that the first string is in the second string.
|
7318
|
-
|
7718
|
+
Raises an exception if the first string is not in the second."""
|
7319
7719
|
self.assertIn(first, second, msg=msg)
|
7320
7720
|
|
7321
7721
|
def assert_not_in(self, first, second, msg=None):
|
7322
7722
|
"""Asserts that the first string is not in the second string.
|
7323
|
-
|
7723
|
+
Raises an exception if the first string is in the second string."""
|
7324
7724
|
self.assertNotIn(first, second, msg=msg)
|
7325
7725
|
|
7326
7726
|
def assert_raises(self, *args, **kwargs):
|
7327
7727
|
"""Asserts that the following block of code raises an exception.
|
7328
|
-
|
7728
|
+
Raises an exception if the block of code has no exception.
|
7329
7729
|
Usage Example =>
|
7330
7730
|
# Verify that the expected exception is raised.
|
7331
7731
|
with self.assert_raises(Exception):
|
@@ -7345,7 +7745,10 @@ class BaseCase(unittest.TestCase):
|
|
7345
7745
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
7346
7746
|
timeout = self.__get_new_timeout(timeout)
|
7347
7747
|
selector, by = self.__recalculate_selector(selector, by)
|
7348
|
-
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):
|
7349
7752
|
return self.__wait_for_shadow_attribute_present(
|
7350
7753
|
selector, attribute, value=value, timeout=timeout
|
7351
7754
|
)
|
@@ -7370,6 +7773,9 @@ class BaseCase(unittest.TestCase):
|
|
7370
7773
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
7371
7774
|
timeout = self.__get_new_timeout(timeout)
|
7372
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
|
7373
7779
|
self.wait_for_attribute(
|
7374
7780
|
selector, attribute, value=value, by=by, timeout=timeout
|
7375
7781
|
)
|
@@ -7419,6 +7825,9 @@ class BaseCase(unittest.TestCase):
|
|
7419
7825
|
but then the title switches over to the actual page title.
|
7420
7826
|
In Recorder Mode, this assertion is skipped because the Recorder
|
7421
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
|
7422
7831
|
self.wait_for_ready_state_complete()
|
7423
7832
|
expected = title.strip()
|
7424
7833
|
actual = self.get_page_title().strip()
|
@@ -7465,6 +7874,9 @@ class BaseCase(unittest.TestCase):
|
|
7465
7874
|
but then the title switches over to the actual page title.
|
7466
7875
|
In Recorder Mode, this assertion is skipped because the Recorder
|
7467
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
|
7468
7880
|
self.wait_for_ready_state_complete()
|
7469
7881
|
expected = substring.strip()
|
7470
7882
|
actual = self.get_page_title().strip()
|
@@ -7508,6 +7920,9 @@ class BaseCase(unittest.TestCase):
|
|
7508
7920
|
|
7509
7921
|
def assert_url(self, url):
|
7510
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
|
7511
7926
|
self.wait_for_ready_state_complete()
|
7512
7927
|
expected = url.strip()
|
7513
7928
|
actual = self.get_current_url().strip()
|
@@ -7543,6 +7958,9 @@ class BaseCase(unittest.TestCase):
|
|
7543
7958
|
|
7544
7959
|
def assert_url_contains(self, substring):
|
7545
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
|
7546
7964
|
self.wait_for_ready_state_complete()
|
7547
7965
|
expected = substring.strip()
|
7548
7966
|
actual = self.get_current_url().strip()
|
@@ -7732,13 +8150,33 @@ class BaseCase(unittest.TestCase):
|
|
7732
8150
|
"""Return True if the url is a valid url."""
|
7733
8151
|
return page_utils.is_valid_url(url)
|
7734
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
|
+
|
7735
8160
|
def is_online(self):
|
7736
8161
|
"""Return True if connected to the Internet."""
|
8162
|
+
if self.__is_cdp_swap_needed():
|
8163
|
+
return self.cdp.evaluate("navigator.onLine;")
|
7737
8164
|
return self.execute_script("return navigator.onLine;")
|
7738
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()
|
8174
|
+
|
7739
8175
|
def is_chromium(self):
|
7740
8176
|
"""Return True if the browser is Chrome or Edge."""
|
7741
8177
|
self.__check_scope()
|
8178
|
+
if self.__is_cdp_swap_needed():
|
8179
|
+
return True
|
7742
8180
|
chromium = False
|
7743
8181
|
if (
|
7744
8182
|
"chrome" in self.driver.capabilities
|
@@ -7851,6 +8289,10 @@ class BaseCase(unittest.TestCase):
|
|
7851
8289
|
self.__check_scope()
|
7852
8290
|
if not timeout:
|
7853
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
|
7854
8296
|
self.wait_for_element_visible(selector, by=by, timeout=timeout)
|
7855
8297
|
if self.recorder_mode and self.__current_url_is_recordable():
|
7856
8298
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -7876,27 +8318,7 @@ class BaseCase(unittest.TestCase):
|
|
7876
8318
|
jQuery commands require a CSS_SELECTOR for finding elements.
|
7877
8319
|
This method should only be used for jQuery/JavaScript actions.
|
7878
8320
|
Pure JavaScript doesn't support using a:contains("LINK_TEXT")."""
|
7879
|
-
|
7880
|
-
return selector
|
7881
|
-
elif by == By.ID:
|
7882
|
-
return "#%s" % selector
|
7883
|
-
elif by == By.CLASS_NAME:
|
7884
|
-
return ".%s" % selector
|
7885
|
-
elif by == By.NAME:
|
7886
|
-
return '[name="%s"]' % selector
|
7887
|
-
elif by == By.TAG_NAME:
|
7888
|
-
return selector
|
7889
|
-
elif by == By.XPATH:
|
7890
|
-
return self.convert_xpath_to_css(selector)
|
7891
|
-
elif by == By.LINK_TEXT:
|
7892
|
-
return 'a:contains("%s")' % selector
|
7893
|
-
elif by == By.PARTIAL_LINK_TEXT:
|
7894
|
-
return 'a:contains("%s")' % selector
|
7895
|
-
else:
|
7896
|
-
raise Exception(
|
7897
|
-
"Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"
|
7898
|
-
% (selector, by)
|
7899
|
-
)
|
8321
|
+
return js_utils.convert_to_css_selector(selector, by)
|
7900
8322
|
|
7901
8323
|
def set_value(
|
7902
8324
|
self, selector, text, by="css selector", timeout=None, scroll=True
|
@@ -7908,6 +8330,9 @@ class BaseCase(unittest.TestCase):
|
|
7908
8330
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
7909
8331
|
timeout = self.__get_new_timeout(timeout)
|
7910
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
|
7911
8336
|
self.wait_for_ready_state_complete()
|
7912
8337
|
self.wait_for_element_present(selector, by=by, timeout=timeout)
|
7913
8338
|
original_selector = selector
|
@@ -7965,17 +8390,15 @@ class BaseCase(unittest.TestCase):
|
|
7965
8390
|
else:
|
7966
8391
|
if the_type == "range" and ":contains\\(" not in css_selector:
|
7967
8392
|
# Some input sliders need a mouse event to trigger listeners.
|
7968
|
-
|
8393
|
+
with suppress(Exception):
|
7969
8394
|
mouse_move_script = (
|
7970
8395
|
"""m_elm = document.querySelector('%s');"""
|
7971
8396
|
"""m_evt = new Event('mousemove');"""
|
7972
8397
|
"""m_elm.dispatchEvent(m_evt);""" % css_selector
|
7973
8398
|
)
|
7974
8399
|
self.execute_script(mouse_move_script)
|
7975
|
-
except Exception:
|
7976
|
-
pass
|
7977
8400
|
elif the_type == "range" and ":contains\\(" in css_selector:
|
7978
|
-
|
8401
|
+
with suppress(Exception):
|
7979
8402
|
element = self.wait_for_element_present(
|
7980
8403
|
original_selector, by=by, timeout=1
|
7981
8404
|
)
|
@@ -7985,8 +8408,6 @@ class BaseCase(unittest.TestCase):
|
|
7985
8408
|
"""m_elm.dispatchEvent(m_evt);"""
|
7986
8409
|
)
|
7987
8410
|
self.execute_script(mouse_move_script, element)
|
7988
|
-
except Exception:
|
7989
|
-
pass
|
7990
8411
|
self.__demo_mode_pause_if_active()
|
7991
8412
|
if not self.demo_mode and not self.slow_mode:
|
7992
8413
|
if self.__needs_minimum_wait():
|
@@ -8006,13 +8427,11 @@ class BaseCase(unittest.TestCase):
|
|
8006
8427
|
text = self.__get_type_checked_text(text)
|
8007
8428
|
self.set_value(selector, text, by=by, timeout=timeout)
|
8008
8429
|
if not text.endswith("\n"):
|
8009
|
-
|
8430
|
+
with suppress(Exception):
|
8010
8431
|
element = page_actions.wait_for_element_present(
|
8011
8432
|
self.driver, selector, by, timeout=0.2
|
8012
8433
|
)
|
8013
8434
|
element.send_keys(" " + Keys.BACK_SPACE)
|
8014
|
-
except Exception:
|
8015
|
-
pass
|
8016
8435
|
|
8017
8436
|
def js_type(self, selector, text, by="css selector", timeout=None):
|
8018
8437
|
"""Same as self.js_update_text()
|
@@ -8132,13 +8551,11 @@ class BaseCase(unittest.TestCase):
|
|
8132
8551
|
)
|
8133
8552
|
element.send_keys(Keys.RETURN)
|
8134
8553
|
else:
|
8135
|
-
|
8554
|
+
with suppress(Exception):
|
8136
8555
|
element = self.wait_for_element_present(
|
8137
8556
|
original_selector, by=original_by, timeout=0.2
|
8138
8557
|
)
|
8139
8558
|
element.send_keys(" " + Keys.BACK_SPACE)
|
8140
|
-
except Exception:
|
8141
|
-
pass
|
8142
8559
|
self.__demo_mode_pause_if_active()
|
8143
8560
|
|
8144
8561
|
def jquery_type(self, selector, text, by="css selector", timeout=None):
|
@@ -8315,10 +8732,8 @@ class BaseCase(unittest.TestCase):
|
|
8315
8732
|
def get_recorded_console_logs(self):
|
8316
8733
|
"""Get console logs recorded after "start_recording_console_logs()"."""
|
8317
8734
|
logs = []
|
8318
|
-
|
8735
|
+
with suppress(Exception):
|
8319
8736
|
logs = self.execute_script("return console.logs;")
|
8320
|
-
except Exception:
|
8321
|
-
pass
|
8322
8737
|
return logs
|
8323
8738
|
|
8324
8739
|
############
|
@@ -8626,12 +9041,15 @@ class BaseCase(unittest.TestCase):
|
|
8626
9041
|
):
|
8627
9042
|
"""Same as self.wait_for_element()"""
|
8628
9043
|
self.__check_scope()
|
9044
|
+
self.__skip_if_esc()
|
8629
9045
|
if not timeout:
|
8630
9046
|
timeout = settings.LARGE_TIMEOUT
|
8631
9047
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
8632
9048
|
timeout = self.__get_new_timeout(timeout)
|
8633
9049
|
original_selector = selector
|
8634
9050
|
selector, by = self.__recalculate_selector(selector, by)
|
9051
|
+
if self.__is_cdp_swap_needed():
|
9052
|
+
return self.cdp.select(selector, timeout=timeout)
|
8635
9053
|
if self.__is_shadow_selector(selector):
|
8636
9054
|
return self.__get_shadow_element(selector, timeout)
|
8637
9055
|
return page_actions.wait_for_element_visible(
|
@@ -8653,7 +9071,9 @@ class BaseCase(unittest.TestCase):
|
|
8653
9071
|
timeout = self.__get_new_timeout(timeout)
|
8654
9072
|
original_selector = selector
|
8655
9073
|
selector, by = self.__recalculate_selector(selector, by)
|
8656
|
-
if self.
|
9074
|
+
if self.__is_cdp_swap_needed():
|
9075
|
+
return self.cdp.select(selector, timeout=timeout)
|
9076
|
+
elif self.__is_shadow_selector(selector):
|
8657
9077
|
# If a shadow selector, use visible instead of clickable
|
8658
9078
|
return self.__wait_for_shadow_element_visible(selector, timeout)
|
8659
9079
|
return page_actions.wait_for_element_clickable(
|
@@ -8679,6 +9099,9 @@ class BaseCase(unittest.TestCase):
|
|
8679
9099
|
timeout = self.__get_new_timeout(timeout)
|
8680
9100
|
original_selector = selector
|
8681
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
|
8682
9105
|
return page_actions.wait_for_element_absent(
|
8683
9106
|
self.driver,
|
8684
9107
|
selector,
|
@@ -8687,6 +9110,9 @@ class BaseCase(unittest.TestCase):
|
|
8687
9110
|
original_selector=original_selector,
|
8688
9111
|
)
|
8689
9112
|
|
9113
|
+
def select_all(self, selector, by="css selector", limit=0):
|
9114
|
+
return self.find_elements(selector, by=by, limit=limit)
|
9115
|
+
|
8690
9116
|
def assert_link(self, link_text, timeout=None):
|
8691
9117
|
"""Same as self.assert_link_text()"""
|
8692
9118
|
self.__check_scope()
|
@@ -8700,7 +9126,7 @@ class BaseCase(unittest.TestCase):
|
|
8700
9126
|
self, selector, by="css selector", timeout=None
|
8701
9127
|
):
|
8702
9128
|
"""Same as self.assert_element_absent()
|
8703
|
-
|
9129
|
+
Raises an exception if the element stays present.
|
8704
9130
|
A hidden element counts as a present element, which fails this assert.
|
8705
9131
|
If you want to assert that elements are hidden instead of nonexistent,
|
8706
9132
|
use assert_element_not_visible() instead.
|
@@ -8738,6 +9164,14 @@ class BaseCase(unittest.TestCase):
|
|
8738
9164
|
"""Same as self.delete_all_cookies()"""
|
8739
9165
|
self.delete_all_cookies()
|
8740
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
|
+
|
8741
9175
|
def assert_no_broken_links(self, multithreaded=True):
|
8742
9176
|
"""Same as self.assert_no_404_errors()"""
|
8743
9177
|
self.assert_no_404_errors(multithreaded=multithreaded)
|
@@ -8753,11 +9187,10 @@ class BaseCase(unittest.TestCase):
|
|
8753
9187
|
def _check_browser(self):
|
8754
9188
|
"""This method raises an exception if the active window is closed.
|
8755
9189
|
(This provides a much cleaner exception message in this situation.)"""
|
9190
|
+
page_actions._reconnect_if_disconnected(self.driver)
|
8756
9191
|
active_window = None
|
8757
|
-
|
9192
|
+
with suppress(Exception):
|
8758
9193
|
active_window = self.driver.current_window_handle # Fails if None
|
8759
|
-
except Exception:
|
8760
|
-
pass
|
8761
9194
|
if not active_window:
|
8762
9195
|
raise NoSuchWindowException("Active window was already closed!")
|
8763
9196
|
|
@@ -8771,10 +9204,8 @@ class BaseCase(unittest.TestCase):
|
|
8771
9204
|
"""
|
8772
9205
|
if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded:
|
8773
9206
|
if not isinstance(msg, str):
|
8774
|
-
|
9207
|
+
with suppress(Exception):
|
8775
9208
|
msg = str(msg)
|
8776
|
-
except Exception:
|
8777
|
-
pass
|
8778
9209
|
sys.stderr.write(msg + "\n")
|
8779
9210
|
else:
|
8780
9211
|
print(msg)
|
@@ -9041,7 +9472,9 @@ class BaseCase(unittest.TestCase):
|
|
9041
9472
|
timeout = self.__get_new_timeout(timeout)
|
9042
9473
|
original_selector = selector
|
9043
9474
|
selector, by = self.__recalculate_selector(selector, by)
|
9044
|
-
if self.
|
9475
|
+
if self.__is_cdp_swap_needed():
|
9476
|
+
return self.cdp.select(selector, timeout=timeout)
|
9477
|
+
elif self.__is_shadow_selector(selector):
|
9045
9478
|
return self.__wait_for_shadow_element_present(selector, timeout)
|
9046
9479
|
return page_actions.wait_for_element_present(
|
9047
9480
|
self.driver,
|
@@ -9061,6 +9494,8 @@ class BaseCase(unittest.TestCase):
|
|
9061
9494
|
timeout = self.__get_new_timeout(timeout)
|
9062
9495
|
original_selector = selector
|
9063
9496
|
selector, by = self.__recalculate_selector(selector, by)
|
9497
|
+
if self.__is_cdp_swap_needed():
|
9498
|
+
return self.cdp.select(selector, timeout=timeout)
|
9064
9499
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9065
9500
|
if self.get_session_storage_item("pause_recorder") == "no":
|
9066
9501
|
if by == By.XPATH:
|
@@ -9102,6 +9537,8 @@ class BaseCase(unittest.TestCase):
|
|
9102
9537
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
9103
9538
|
timeout = self.__get_new_timeout(timeout)
|
9104
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)
|
9105
9542
|
return js_utils.wait_for_css_query_selector(
|
9106
9543
|
self.driver, css_selector, timeout
|
9107
9544
|
)
|
@@ -9121,6 +9558,9 @@ class BaseCase(unittest.TestCase):
|
|
9121
9558
|
if isinstance(selector, list):
|
9122
9559
|
self.assert_elements_present(selector, by=by, timeout=timeout)
|
9123
9560
|
return True
|
9561
|
+
if self.__is_cdp_swap_needed():
|
9562
|
+
self.cdp.assert_element_present(selector)
|
9563
|
+
return True
|
9124
9564
|
if self.__is_shadow_selector(selector):
|
9125
9565
|
self.__assert_shadow_element_present(selector)
|
9126
9566
|
return True
|
@@ -9188,13 +9628,16 @@ class BaseCase(unittest.TestCase):
|
|
9188
9628
|
|
9189
9629
|
def assert_element(self, selector, by="css selector", timeout=None):
|
9190
9630
|
"""Similar to wait_for_element_visible(), but returns nothing.
|
9191
|
-
As above,
|
9631
|
+
As above, raises an exception if nothing can be found.
|
9192
9632
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9193
9633
|
self.__check_scope()
|
9194
9634
|
if not timeout:
|
9195
9635
|
timeout = settings.SMALL_TIMEOUT
|
9196
9636
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9197
9637
|
timeout = self.__get_new_timeout(timeout)
|
9638
|
+
if self.__is_cdp_swap_needed():
|
9639
|
+
self.cdp.assert_element(selector)
|
9640
|
+
return True
|
9198
9641
|
if isinstance(selector, list):
|
9199
9642
|
self.assert_elements(selector, by=by, timeout=timeout)
|
9200
9643
|
return True
|
@@ -9228,7 +9671,7 @@ class BaseCase(unittest.TestCase):
|
|
9228
9671
|
self, selector, by="css selector", timeout=None
|
9229
9672
|
):
|
9230
9673
|
"""Same as self.assert_element()
|
9231
|
-
As above,
|
9674
|
+
As above, raises an exception if nothing can be found."""
|
9232
9675
|
self.__check_scope()
|
9233
9676
|
if not timeout:
|
9234
9677
|
timeout = settings.SMALL_TIMEOUT
|
@@ -9306,7 +9749,7 @@ class BaseCase(unittest.TestCase):
|
|
9306
9749
|
############
|
9307
9750
|
|
9308
9751
|
def wait_for_text_visible(
|
9309
|
-
self, text, selector="
|
9752
|
+
self, text, selector="body", by="css selector", timeout=None
|
9310
9753
|
):
|
9311
9754
|
self.__check_scope()
|
9312
9755
|
if not timeout:
|
@@ -9315,14 +9758,16 @@ class BaseCase(unittest.TestCase):
|
|
9315
9758
|
timeout = self.__get_new_timeout(timeout)
|
9316
9759
|
text = self.__get_type_checked_text(text)
|
9317
9760
|
selector, by = self.__recalculate_selector(selector, by)
|
9318
|
-
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):
|
9319
9764
|
return self.__wait_for_shadow_text_visible(text, selector, timeout)
|
9320
9765
|
return page_actions.wait_for_text_visible(
|
9321
9766
|
self.driver, text, selector, by, timeout
|
9322
9767
|
)
|
9323
9768
|
|
9324
9769
|
def wait_for_exact_text_visible(
|
9325
|
-
self, text, selector="
|
9770
|
+
self, text, selector="body", by="css selector", timeout=None
|
9326
9771
|
):
|
9327
9772
|
self.__check_scope()
|
9328
9773
|
if not timeout:
|
@@ -9339,7 +9784,7 @@ class BaseCase(unittest.TestCase):
|
|
9339
9784
|
)
|
9340
9785
|
|
9341
9786
|
def wait_for_non_empty_text_visible(
|
9342
|
-
self, selector="
|
9787
|
+
self, selector="body", by="css selector", timeout=None
|
9343
9788
|
):
|
9344
9789
|
"""Searches for any text in the element of the given selector.
|
9345
9790
|
Returns the element if it has visible text within the timeout.
|
@@ -9360,7 +9805,7 @@ class BaseCase(unittest.TestCase):
|
|
9360
9805
|
)
|
9361
9806
|
|
9362
9807
|
def wait_for_text(
|
9363
|
-
self, text, selector="
|
9808
|
+
self, text, selector="body", by="css selector", timeout=None
|
9364
9809
|
):
|
9365
9810
|
"""The shorter version of wait_for_text_visible()"""
|
9366
9811
|
self.__check_scope()
|
@@ -9373,7 +9818,7 @@ class BaseCase(unittest.TestCase):
|
|
9373
9818
|
)
|
9374
9819
|
|
9375
9820
|
def wait_for_exact_text(
|
9376
|
-
self, text, selector="
|
9821
|
+
self, text, selector="body", by="css selector", timeout=None
|
9377
9822
|
):
|
9378
9823
|
"""The shorter version of wait_for_exact_text_visible()"""
|
9379
9824
|
self.__check_scope()
|
@@ -9386,7 +9831,7 @@ class BaseCase(unittest.TestCase):
|
|
9386
9831
|
)
|
9387
9832
|
|
9388
9833
|
def wait_for_non_empty_text(
|
9389
|
-
self, selector="
|
9834
|
+
self, selector="body", by="css selector", timeout=None
|
9390
9835
|
):
|
9391
9836
|
"""The shorter version of wait_for_non_empty_text_visible()"""
|
9392
9837
|
self.__check_scope()
|
@@ -9399,7 +9844,7 @@ class BaseCase(unittest.TestCase):
|
|
9399
9844
|
)
|
9400
9845
|
|
9401
9846
|
def find_text(
|
9402
|
-
self, text, selector="
|
9847
|
+
self, text, selector="body", by="css selector", timeout=None
|
9403
9848
|
):
|
9404
9849
|
"""Same as wait_for_text_visible() - returns the element"""
|
9405
9850
|
self.__check_scope()
|
@@ -9412,7 +9857,7 @@ class BaseCase(unittest.TestCase):
|
|
9412
9857
|
)
|
9413
9858
|
|
9414
9859
|
def find_exact_text(
|
9415
|
-
self, text, selector="
|
9860
|
+
self, text, selector="body", by="css selector", timeout=None
|
9416
9861
|
):
|
9417
9862
|
"""Same as wait_for_exact_text_visible() - returns the element"""
|
9418
9863
|
self.__check_scope()
|
@@ -9425,7 +9870,7 @@ class BaseCase(unittest.TestCase):
|
|
9425
9870
|
)
|
9426
9871
|
|
9427
9872
|
def find_non_empty_text(
|
9428
|
-
self, selector="
|
9873
|
+
self, selector="body", by="css selector", timeout=None
|
9429
9874
|
):
|
9430
9875
|
"""Same as wait_for_non_empty_text_visible() - returns the element"""
|
9431
9876
|
self.__check_scope()
|
@@ -9438,7 +9883,7 @@ class BaseCase(unittest.TestCase):
|
|
9438
9883
|
)
|
9439
9884
|
|
9440
9885
|
def assert_text_visible(
|
9441
|
-
self, text, selector="
|
9886
|
+
self, text, selector="body", by="css selector", timeout=None
|
9442
9887
|
):
|
9443
9888
|
"""Same as assert_text()"""
|
9444
9889
|
self.__check_scope()
|
@@ -9449,11 +9894,12 @@ class BaseCase(unittest.TestCase):
|
|
9449
9894
|
return self.assert_text(text, selector, by=by, timeout=timeout)
|
9450
9895
|
|
9451
9896
|
def assert_text(
|
9452
|
-
self, text, selector="
|
9897
|
+
self, text, selector="body", by="css selector", timeout=None
|
9453
9898
|
):
|
9454
9899
|
"""Similar to wait_for_text_visible()
|
9455
9900
|
Raises an exception if the element or the text is not found.
|
9456
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.
|
9457
9903
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9458
9904
|
self.__check_scope()
|
9459
9905
|
if not timeout:
|
@@ -9462,26 +9908,50 @@ class BaseCase(unittest.TestCase):
|
|
9462
9908
|
timeout = self.__get_new_timeout(timeout)
|
9463
9909
|
original_selector = selector
|
9464
9910
|
selector, by = self.__recalculate_selector(selector, by)
|
9465
|
-
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):
|
9466
9937
|
self.__assert_shadow_text_visible(text, selector, timeout)
|
9467
9938
|
return True
|
9468
|
-
|
9469
|
-
|
9470
|
-
|
9471
|
-
|
9472
|
-
|
9473
|
-
|
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
|
9474
9946
|
|
9475
|
-
|
9476
|
-
|
9477
|
-
|
9478
|
-
|
9479
|
-
|
9480
|
-
|
9481
|
-
|
9482
|
-
|
9483
|
-
)
|
9484
|
-
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
|
+
)
|
9485
9955
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9486
9956
|
if self.get_session_storage_item("pause_recorder") == "no":
|
9487
9957
|
if by == By.XPATH:
|
@@ -9494,7 +9964,7 @@ class BaseCase(unittest.TestCase):
|
|
9494
9964
|
return True
|
9495
9965
|
|
9496
9966
|
def assert_exact_text(
|
9497
|
-
self, text, selector="
|
9967
|
+
self, text, selector="body", by="css selector", timeout=None
|
9498
9968
|
):
|
9499
9969
|
"""Similar to assert_text(), but the text must be exact,
|
9500
9970
|
rather than exist as a subset of the full text.
|
@@ -9508,6 +9978,9 @@ class BaseCase(unittest.TestCase):
|
|
9508
9978
|
timeout = self.__get_new_timeout(timeout)
|
9509
9979
|
original_selector = selector
|
9510
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
|
9511
9984
|
if self.__is_shadow_selector(selector):
|
9512
9985
|
self.__assert_exact_shadow_text_visible(text, selector, timeout)
|
9513
9986
|
return True
|
@@ -9523,11 +9996,7 @@ class BaseCase(unittest.TestCase):
|
|
9523
9996
|
a_t = SD.translate_assert_exact_text(self._language)
|
9524
9997
|
i_n = SD.translate_in(self._language)
|
9525
9998
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
9526
|
-
a_t,
|
9527
|
-
text,
|
9528
|
-
i_n,
|
9529
|
-
by.upper(),
|
9530
|
-
selector,
|
9999
|
+
a_t, text, i_n, by.upper(), selector
|
9531
10000
|
)
|
9532
10001
|
self.__highlight_with_assert_success(messenger_post, selector, by)
|
9533
10002
|
if self.recorder_mode and self.__current_url_is_recordable():
|
@@ -9542,7 +10011,7 @@ class BaseCase(unittest.TestCase):
|
|
9542
10011
|
return True
|
9543
10012
|
|
9544
10013
|
def assert_non_empty_text(
|
9545
|
-
self, selector="
|
10014
|
+
self, selector="body", by="css selector", timeout=None
|
9546
10015
|
):
|
9547
10016
|
"""Assert that the element has any non-empty text visible.
|
9548
10017
|
Raises an exception if the element has no text within the timeout.
|
@@ -9567,10 +10036,7 @@ class BaseCase(unittest.TestCase):
|
|
9567
10036
|
a_t = SD.translate_assert_non_empty_text(self._language)
|
9568
10037
|
i_n = SD.translate_in(self._language)
|
9569
10038
|
messenger_post = "<b>%s</b> %s %s: %s" % (
|
9570
|
-
a_t,
|
9571
|
-
i_n,
|
9572
|
-
by.upper(),
|
9573
|
-
selector,
|
10039
|
+
a_t, i_n, by.upper(), selector
|
9574
10040
|
)
|
9575
10041
|
self.__highlight_with_assert_success(messenger_post, selector, by)
|
9576
10042
|
if self.recorder_mode and self.__current_url_is_recordable():
|
@@ -9665,13 +10131,16 @@ class BaseCase(unittest.TestCase):
|
|
9665
10131
|
|
9666
10132
|
def assert_link_text(self, link_text, timeout=None):
|
9667
10133
|
"""Similar to wait_for_link_text_visible(), but returns nothing.
|
9668
|
-
As above,
|
10134
|
+
As above, raises an exception if nothing can be found.
|
9669
10135
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9670
10136
|
self.__check_scope()
|
9671
10137
|
if not timeout:
|
9672
10138
|
timeout = settings.SMALL_TIMEOUT
|
9673
10139
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9674
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
|
9675
10144
|
self.wait_for_link_text_visible(link_text, timeout=timeout)
|
9676
10145
|
if self.demo_mode:
|
9677
10146
|
a_t = "ASSERT LINK TEXT"
|
@@ -9714,7 +10183,7 @@ class BaseCase(unittest.TestCase):
|
|
9714
10183
|
|
9715
10184
|
def assert_partial_link_text(self, partial_link_text, timeout=None):
|
9716
10185
|
"""Similar to wait_for_partial_link_text(), but returns nothing.
|
9717
|
-
As above,
|
10186
|
+
As above, raises an exception if nothing can be found.
|
9718
10187
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9719
10188
|
self.__check_scope()
|
9720
10189
|
if not timeout:
|
@@ -9760,7 +10229,7 @@ class BaseCase(unittest.TestCase):
|
|
9760
10229
|
|
9761
10230
|
def assert_element_absent(self, selector, by="css selector", timeout=None):
|
9762
10231
|
"""Similar to wait_for_element_absent()
|
9763
|
-
As above,
|
10232
|
+
As above, raises an exception if the element stays present.
|
9764
10233
|
A hidden element counts as a present element, which fails this assert.
|
9765
10234
|
If you want to assert that elements are hidden instead of nonexistent,
|
9766
10235
|
use assert_element_not_visible() instead.
|
@@ -9771,6 +10240,9 @@ class BaseCase(unittest.TestCase):
|
|
9771
10240
|
timeout = settings.SMALL_TIMEOUT
|
9772
10241
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9773
10242
|
timeout = self.__get_new_timeout(timeout)
|
10243
|
+
if self.__is_cdp_swap_needed():
|
10244
|
+
self.cdp.assert_element_absent(selector)
|
10245
|
+
return True
|
9774
10246
|
self.wait_for_element_absent(selector, by=by, timeout=timeout)
|
9775
10247
|
return True
|
9776
10248
|
|
@@ -9789,6 +10261,9 @@ class BaseCase(unittest.TestCase):
|
|
9789
10261
|
timeout = self.__get_new_timeout(timeout)
|
9790
10262
|
original_selector = selector
|
9791
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
|
9792
10267
|
return page_actions.wait_for_element_not_visible(
|
9793
10268
|
self.driver,
|
9794
10269
|
selector,
|
@@ -9801,13 +10276,16 @@ class BaseCase(unittest.TestCase):
|
|
9801
10276
|
self, selector, by="css selector", timeout=None
|
9802
10277
|
):
|
9803
10278
|
"""Similar to wait_for_element_not_visible()
|
9804
|
-
As above,
|
10279
|
+
As above, raises an exception if the element stays visible.
|
9805
10280
|
Returns True if successful. Default timeout = SMALL_TIMEOUT."""
|
9806
10281
|
self.__check_scope()
|
9807
10282
|
if not timeout:
|
9808
10283
|
timeout = settings.SMALL_TIMEOUT
|
9809
10284
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
9810
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
|
9811
10289
|
self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
|
9812
10290
|
if self.recorder_mode and self.__current_url_is_recordable():
|
9813
10291
|
if self.get_session_storage_item("pause_recorder") == "no":
|
@@ -9820,7 +10298,7 @@ class BaseCase(unittest.TestCase):
|
|
9820
10298
|
############
|
9821
10299
|
|
9822
10300
|
def wait_for_text_not_visible(
|
9823
|
-
self, text, selector="
|
10301
|
+
self, text, selector="body", by="css selector", timeout=None
|
9824
10302
|
):
|
9825
10303
|
self.__check_scope()
|
9826
10304
|
if not timeout:
|
@@ -9833,7 +10311,7 @@ class BaseCase(unittest.TestCase):
|
|
9833
10311
|
)
|
9834
10312
|
|
9835
10313
|
def wait_for_exact_text_not_visible(
|
9836
|
-
self, text, selector="
|
10314
|
+
self, text, selector="body", by="css selector", timeout=None
|
9837
10315
|
):
|
9838
10316
|
self.__check_scope()
|
9839
10317
|
if not timeout:
|
@@ -9846,7 +10324,7 @@ class BaseCase(unittest.TestCase):
|
|
9846
10324
|
)
|
9847
10325
|
|
9848
10326
|
def assert_text_not_visible(
|
9849
|
-
self, text, selector="
|
10327
|
+
self, text, selector="body", by="css selector", timeout=None
|
9850
10328
|
):
|
9851
10329
|
"""Similar to wait_for_text_not_visible()
|
9852
10330
|
Raises an exception if the text is still visible after timeout.
|
@@ -9867,7 +10345,7 @@ class BaseCase(unittest.TestCase):
|
|
9867
10345
|
return True
|
9868
10346
|
|
9869
10347
|
def assert_exact_text_not_visible(
|
9870
|
-
self, text, selector="
|
10348
|
+
self, text, selector="body", by="css selector", timeout=None
|
9871
10349
|
):
|
9872
10350
|
"""Similar to wait_for_exact_text_not_visible()
|
9873
10351
|
Raises an exception if the exact text is still visible after timeout.
|
@@ -10117,7 +10595,7 @@ class BaseCase(unittest.TestCase):
|
|
10117
10595
|
countdown_on = True
|
10118
10596
|
countdown = 3
|
10119
10597
|
minified_exception += line + "\n"
|
10120
|
-
elif line.startswith("+"
|
10598
|
+
elif line.startswith(("+", "-")):
|
10121
10599
|
minified_exception += line + "\n"
|
10122
10600
|
elif line.startswith("?"):
|
10123
10601
|
minified_exception += line + "\n"
|
@@ -10166,8 +10644,6 @@ class BaseCase(unittest.TestCase):
|
|
10166
10644
|
shutil.copy(latest_png_path, latest_copy_path)
|
10167
10645
|
if len(self.__visual_baseline_copies) != 1:
|
10168
10646
|
return # Skip the rest when deferred visual asserts are used
|
10169
|
-
from seleniumbase.core import visual_helper
|
10170
|
-
|
10171
10647
|
the_html = visual_helper.get_sbs_html()
|
10172
10648
|
file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
|
10173
10649
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
@@ -10254,12 +10730,10 @@ class BaseCase(unittest.TestCase):
|
|
10254
10730
|
self.check_window(name="github_page", level=2)
|
10255
10731
|
self.check_window(name="wikipedia_page", level=3) """
|
10256
10732
|
self.wait_for_ready_state_complete()
|
10257
|
-
|
10733
|
+
with suppress(Exception):
|
10258
10734
|
self.wait_for_element_visible(
|
10259
10735
|
"body", timeout=settings.MINI_TIMEOUT
|
10260
10736
|
)
|
10261
|
-
except Exception:
|
10262
|
-
pass
|
10263
10737
|
if self.__needs_minimum_wait():
|
10264
10738
|
time.sleep(0.08)
|
10265
10739
|
if level == "0":
|
@@ -10285,7 +10759,6 @@ class BaseCase(unittest.TestCase):
|
|
10285
10759
|
if not name or len(name) < 1:
|
10286
10760
|
name = "default"
|
10287
10761
|
name = str(name)
|
10288
|
-
from seleniumbase.core import visual_helper
|
10289
10762
|
|
10290
10763
|
visual_helper.visual_baseline_folder_setup()
|
10291
10764
|
baseline_dir = constants.VisualBaseline.STORAGE_FOLDER
|
@@ -10502,6 +10975,12 @@ class BaseCase(unittest.TestCase):
|
|
10502
10975
|
|
10503
10976
|
############
|
10504
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
|
+
|
10505
10984
|
def __check_scope(self):
|
10506
10985
|
if hasattr(self, "browser"): # self.browser stores the type of browser
|
10507
10986
|
return # All good: setUp() already initialized variables in "self"
|
@@ -10568,14 +11047,12 @@ class BaseCase(unittest.TestCase):
|
|
10568
11047
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10569
11048
|
timeout = self.__get_new_timeout(timeout)
|
10570
11049
|
self.__deferred_assert_count += 1
|
10571
|
-
|
11050
|
+
with suppress(Exception):
|
10572
11051
|
url = self.get_current_url()
|
10573
11052
|
if url == self.__last_url_of_deferred_assert:
|
10574
11053
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10575
11054
|
else:
|
10576
11055
|
self.__last_url_of_deferred_assert = url
|
10577
|
-
except Exception:
|
10578
|
-
pass
|
10579
11056
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10580
11057
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10581
11058
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10605,14 +11082,12 @@ class BaseCase(unittest.TestCase):
|
|
10605
11082
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10606
11083
|
timeout = self.__get_new_timeout(timeout)
|
10607
11084
|
self.__deferred_assert_count += 1
|
10608
|
-
|
11085
|
+
with suppress(Exception):
|
10609
11086
|
url = self.get_current_url()
|
10610
11087
|
if url == self.__last_url_of_deferred_assert:
|
10611
11088
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10612
11089
|
else:
|
10613
11090
|
self.__last_url_of_deferred_assert = url
|
10614
|
-
except Exception:
|
10615
|
-
pass
|
10616
11091
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10617
11092
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10618
11093
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10627,7 +11102,7 @@ class BaseCase(unittest.TestCase):
|
|
10627
11102
|
return False
|
10628
11103
|
|
10629
11104
|
def deferred_assert_text(
|
10630
|
-
self, text, selector="
|
11105
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10631
11106
|
):
|
10632
11107
|
"""A non-terminating assertion for text from an element on a page.
|
10633
11108
|
Failures will be saved until the process_deferred_asserts()
|
@@ -10642,14 +11117,12 @@ class BaseCase(unittest.TestCase):
|
|
10642
11117
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10643
11118
|
timeout = self.__get_new_timeout(timeout)
|
10644
11119
|
self.__deferred_assert_count += 1
|
10645
|
-
|
11120
|
+
with suppress(Exception):
|
10646
11121
|
url = self.get_current_url()
|
10647
11122
|
if url == self.__last_url_of_deferred_assert:
|
10648
11123
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10649
11124
|
else:
|
10650
11125
|
self.__last_url_of_deferred_assert = url
|
10651
|
-
except Exception:
|
10652
|
-
pass
|
10653
11126
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10654
11127
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10655
11128
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10665,7 +11138,7 @@ class BaseCase(unittest.TestCase):
|
|
10665
11138
|
return False
|
10666
11139
|
|
10667
11140
|
def deferred_assert_exact_text(
|
10668
|
-
self, text, selector="
|
11141
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10669
11142
|
):
|
10670
11143
|
"""A non-terminating assertion for exact text from an element.
|
10671
11144
|
Failures will be saved until the process_deferred_asserts()
|
@@ -10680,14 +11153,12 @@ class BaseCase(unittest.TestCase):
|
|
10680
11153
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10681
11154
|
timeout = self.__get_new_timeout(timeout)
|
10682
11155
|
self.__deferred_assert_count += 1
|
10683
|
-
|
11156
|
+
with suppress(Exception):
|
10684
11157
|
url = self.get_current_url()
|
10685
11158
|
if url == self.__last_url_of_deferred_assert:
|
10686
11159
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10687
11160
|
else:
|
10688
11161
|
self.__last_url_of_deferred_assert = url
|
10689
|
-
except Exception:
|
10690
|
-
pass
|
10691
11162
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10692
11163
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10693
11164
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10706,7 +11177,7 @@ class BaseCase(unittest.TestCase):
|
|
10706
11177
|
|
10707
11178
|
def deferred_assert_non_empty_text(
|
10708
11179
|
self,
|
10709
|
-
selector="
|
11180
|
+
selector="body",
|
10710
11181
|
by="css selector",
|
10711
11182
|
timeout=None,
|
10712
11183
|
fs=False,
|
@@ -10724,14 +11195,12 @@ class BaseCase(unittest.TestCase):
|
|
10724
11195
|
if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:
|
10725
11196
|
timeout = self.__get_new_timeout(timeout)
|
10726
11197
|
self.__deferred_assert_count += 1
|
10727
|
-
|
11198
|
+
with suppress(Exception):
|
10728
11199
|
url = self.get_current_url()
|
10729
11200
|
if url == self.__last_url_of_deferred_assert:
|
10730
11201
|
timeout = 0.6 # Was already on page (full wait not needed)
|
10731
11202
|
else:
|
10732
11203
|
self.__last_url_of_deferred_assert = url
|
10733
|
-
except Exception:
|
10734
|
-
pass
|
10735
11204
|
if self.recorder_mode and self.__current_url_is_recordable():
|
10736
11205
|
if self.get_session_storage_item("pause_recorder") == "no":
|
10737
11206
|
time_stamp = self.execute_script("return Date.now();")
|
@@ -10828,7 +11297,7 @@ class BaseCase(unittest.TestCase):
|
|
10828
11297
|
)
|
10829
11298
|
|
10830
11299
|
def delayed_assert_text(
|
10831
|
-
self, text, selector="
|
11300
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10832
11301
|
):
|
10833
11302
|
"""Same as self.deferred_assert_text()"""
|
10834
11303
|
return self.deferred_assert_text(
|
@@ -10836,7 +11305,7 @@ class BaseCase(unittest.TestCase):
|
|
10836
11305
|
)
|
10837
11306
|
|
10838
11307
|
def delayed_assert_exact_text(
|
10839
|
-
self, text, selector="
|
11308
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
10840
11309
|
):
|
10841
11310
|
"""Same as self.deferred_assert_exact_text()"""
|
10842
11311
|
return self.deferred_assert_exact_text(
|
@@ -10845,7 +11314,7 @@ class BaseCase(unittest.TestCase):
|
|
10845
11314
|
|
10846
11315
|
def delayed_assert_non_empty_text(
|
10847
11316
|
self,
|
10848
|
-
selector="
|
11317
|
+
selector="body",
|
10849
11318
|
by="css selector",
|
10850
11319
|
timeout=None,
|
10851
11320
|
fs=False,
|
@@ -11167,10 +11636,8 @@ class BaseCase(unittest.TestCase):
|
|
11167
11636
|
if saved_presentations_folder.endswith("/"):
|
11168
11637
|
saved_presentations_folder = saved_presentations_folder[:-1]
|
11169
11638
|
if not os.path.exists(saved_presentations_folder):
|
11170
|
-
|
11639
|
+
with suppress(Exception):
|
11171
11640
|
os.makedirs(saved_presentations_folder)
|
11172
|
-
except Exception:
|
11173
|
-
pass
|
11174
11641
|
file_path = os.path.join(saved_presentations_folder, filename)
|
11175
11642
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
11176
11643
|
out_file.writelines(the_html)
|
@@ -11224,7 +11691,7 @@ class BaseCase(unittest.TestCase):
|
|
11224
11691
|
self._presentation_slides[name].pop()
|
11225
11692
|
self.open_html_file(file_path)
|
11226
11693
|
presentation_folder = constants.Presentations.SAVED_FOLDER
|
11227
|
-
|
11694
|
+
with suppress(Exception):
|
11228
11695
|
while (
|
11229
11696
|
len(self.driver.window_handles) > 0
|
11230
11697
|
and presentation_folder in self.get_current_url()
|
@@ -11235,8 +11702,6 @@ class BaseCase(unittest.TestCase):
|
|
11235
11702
|
):
|
11236
11703
|
break
|
11237
11704
|
time.sleep(0.05)
|
11238
|
-
except Exception:
|
11239
|
-
pass
|
11240
11705
|
|
11241
11706
|
############
|
11242
11707
|
|
@@ -11866,10 +12331,8 @@ class BaseCase(unittest.TestCase):
|
|
11866
12331
|
if saved_charts_folder.endswith("/"):
|
11867
12332
|
saved_charts_folder = saved_charts_folder[:-1]
|
11868
12333
|
if not os.path.exists(saved_charts_folder):
|
11869
|
-
|
12334
|
+
with suppress(Exception):
|
11870
12335
|
os.makedirs(saved_charts_folder)
|
11871
|
-
except Exception:
|
11872
|
-
pass
|
11873
12336
|
file_path = os.path.join(saved_charts_folder, filename)
|
11874
12337
|
out_file = codecs.open(file_path, "w+", encoding="utf-8")
|
11875
12338
|
out_file.writelines(the_html)
|
@@ -11909,17 +12372,15 @@ class BaseCase(unittest.TestCase):
|
|
11909
12372
|
self.open_html_file(file_path)
|
11910
12373
|
chart_folder = constants.Charts.SAVED_FOLDER
|
11911
12374
|
if interval == 0:
|
11912
|
-
|
12375
|
+
with suppress(Exception):
|
11913
12376
|
print("\n*** Close the browser window to continue ***")
|
11914
12377
|
# Will also continue if manually navigating to a new page
|
11915
12378
|
while len(self.driver.window_handles) > 0 and (
|
11916
12379
|
chart_folder in self.get_current_url()
|
11917
12380
|
):
|
11918
12381
|
time.sleep(0.05)
|
11919
|
-
except Exception:
|
11920
|
-
pass
|
11921
12382
|
else:
|
11922
|
-
|
12383
|
+
with suppress(Exception):
|
11923
12384
|
start_ms = time.time() * 1000.0
|
11924
12385
|
stop_ms = start_ms + (interval * 1000.0)
|
11925
12386
|
for x in range(int(interval * 10)):
|
@@ -11931,8 +12392,6 @@ class BaseCase(unittest.TestCase):
|
|
11931
12392
|
if chart_folder not in self.get_current_url():
|
11932
12393
|
break
|
11933
12394
|
time.sleep(0.1)
|
11934
|
-
except Exception:
|
11935
|
-
pass
|
11936
12395
|
|
11937
12396
|
def extract_chart(self, chart_name=None):
|
11938
12397
|
"""Extracts the HTML from a SeleniumBase-generated chart.
|
@@ -12744,10 +13203,8 @@ class BaseCase(unittest.TestCase):
|
|
12744
13203
|
)
|
12745
13204
|
time.sleep(0.02)
|
12746
13205
|
jf = "document.querySelector('.jconfirm-box').focus();"
|
12747
|
-
|
13206
|
+
with suppress(Exception):
|
12748
13207
|
self.execute_script(jf)
|
12749
|
-
except Exception:
|
12750
|
-
pass
|
12751
13208
|
waiting_for_response = True
|
12752
13209
|
while waiting_for_response:
|
12753
13210
|
time.sleep(0.05)
|
@@ -12819,10 +13276,8 @@ class BaseCase(unittest.TestCase):
|
|
12819
13276
|
)
|
12820
13277
|
time.sleep(0.02)
|
12821
13278
|
jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
|
12822
|
-
|
13279
|
+
with suppress(Exception):
|
12823
13280
|
self.execute_script(jf)
|
12824
|
-
except Exception:
|
12825
|
-
pass
|
12826
13281
|
waiting_for_response = True
|
12827
13282
|
while waiting_for_response:
|
12828
13283
|
time.sleep(0.05)
|
@@ -12883,10 +13338,8 @@ class BaseCase(unittest.TestCase):
|
|
12883
13338
|
)
|
12884
13339
|
time.sleep(0.02)
|
12885
13340
|
jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();"
|
12886
|
-
|
13341
|
+
with suppress(Exception):
|
12887
13342
|
self.execute_script(jf)
|
12888
|
-
except Exception:
|
12889
|
-
pass
|
12890
13343
|
waiting_for_response = True
|
12891
13344
|
while waiting_for_response:
|
12892
13345
|
time.sleep(0.05)
|
@@ -12961,12 +13414,10 @@ class BaseCase(unittest.TestCase):
|
|
12961
13414
|
if not page_actions.is_element_clickable(
|
12962
13415
|
self.driver, selector, by
|
12963
13416
|
):
|
12964
|
-
|
13417
|
+
with suppress(Exception):
|
12965
13418
|
self.wait_for_element_clickable(
|
12966
13419
|
selector, by, timeout=1.8
|
12967
13420
|
)
|
12968
|
-
except Exception:
|
12969
|
-
pass
|
12970
13421
|
# If the regular mouse-simulated click fails, do a basic JS click
|
12971
13422
|
script = (
|
12972
13423
|
"""document.querySelector('%s').click();"""
|
@@ -13042,8 +13493,6 @@ class BaseCase(unittest.TestCase):
|
|
13042
13493
|
timeout=None,
|
13043
13494
|
center=None,
|
13044
13495
|
):
|
13045
|
-
from selenium.webdriver.common.action_chains import ActionChains
|
13046
|
-
|
13047
13496
|
self.wait_for_ready_state_complete()
|
13048
13497
|
if self.__needs_minimum_wait():
|
13049
13498
|
time.sleep(0.14)
|
@@ -13240,7 +13689,7 @@ class BaseCase(unittest.TestCase):
|
|
13240
13689
|
for dropdown in matching_dropdowns:
|
13241
13690
|
# The same class names might be used for multiple dropdowns
|
13242
13691
|
if dropdown.is_displayed():
|
13243
|
-
|
13692
|
+
with suppress(Exception):
|
13244
13693
|
try:
|
13245
13694
|
page_actions.hover_element(
|
13246
13695
|
self.driver,
|
@@ -13261,9 +13710,6 @@ class BaseCase(unittest.TestCase):
|
|
13261
13710
|
timeout=0.12,
|
13262
13711
|
)
|
13263
13712
|
return True
|
13264
|
-
except Exception:
|
13265
|
-
pass
|
13266
|
-
|
13267
13713
|
return False
|
13268
13714
|
|
13269
13715
|
def __get_href_from_partial_link_text(self, link_text, hard_fail=True):
|
@@ -13304,7 +13750,7 @@ class BaseCase(unittest.TestCase):
|
|
13304
13750
|
for dropdown in matching_dropdowns:
|
13305
13751
|
# The same class names might be used for multiple dropdowns
|
13306
13752
|
if dropdown.is_displayed():
|
13307
|
-
|
13753
|
+
with suppress(Exception):
|
13308
13754
|
try:
|
13309
13755
|
page_actions.hover_element(
|
13310
13756
|
self.driver, dropdown
|
@@ -13326,8 +13772,6 @@ class BaseCase(unittest.TestCase):
|
|
13326
13772
|
timeout=0.12,
|
13327
13773
|
)
|
13328
13774
|
return True
|
13329
|
-
except Exception:
|
13330
|
-
pass
|
13331
13775
|
return False
|
13332
13776
|
|
13333
13777
|
def __recalculate_selector(self, selector, by, xp_ok=True):
|
@@ -13351,7 +13795,8 @@ class BaseCase(unittest.TestCase):
|
|
13351
13795
|
if self.get_current_url() == "about:blank":
|
13352
13796
|
self.switch_to_window(current_window)
|
13353
13797
|
except Exception:
|
13354
|
-
|
13798
|
+
with suppress(Exception):
|
13799
|
+
self.switch_to_window(current_window)
|
13355
13800
|
|
13356
13801
|
def __needs_minimum_wait(self):
|
13357
13802
|
if (
|
@@ -13387,6 +13832,7 @@ class BaseCase(unittest.TestCase):
|
|
13387
13832
|
self.slow_scroll_to(selector, by=by)
|
13388
13833
|
|
13389
13834
|
def __demo_mode_highlight_if_active(self, selector, by):
|
13835
|
+
self.__skip_if_esc()
|
13390
13836
|
if self.demo_mode:
|
13391
13837
|
# Includes self.slow_scroll_to(selector, by=by) by default
|
13392
13838
|
self.__highlight(selector, by=by)
|
@@ -13434,7 +13880,8 @@ class BaseCase(unittest.TestCase):
|
|
13434
13880
|
js_utils.scroll_to_element(self.driver, element)
|
13435
13881
|
|
13436
13882
|
def __highlight_with_js(self, selector, loops, o_bs):
|
13437
|
-
self.
|
13883
|
+
if not self.__is_cdp_swap_needed():
|
13884
|
+
self.wait_for_ready_state_complete()
|
13438
13885
|
js_utils.highlight_with_js(self.driver, selector, loops, o_bs)
|
13439
13886
|
|
13440
13887
|
def __highlight_element_with_js(self, element, loops, o_bs):
|
@@ -13549,23 +13996,112 @@ class BaseCase(unittest.TestCase):
|
|
13549
13996
|
pass # JQuery probably couldn't load. Skip highlighting.
|
13550
13997
|
time.sleep(0.065)
|
13551
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
|
+
|
13552
14086
|
def __activate_virtual_display_as_needed(self):
|
13553
|
-
"""
|
14087
|
+
"""This is only needed on Linux.
|
13554
14088
|
The "--xvfb" arg is still useful, as it prevents headless mode,
|
13555
14089
|
which is the default mode on Linux unless using another arg."""
|
13556
14090
|
if "linux" in sys.platform and (not self.headed or self.xvfb):
|
13557
|
-
|
13558
|
-
|
14091
|
+
pip_find_lock = fasteners.InterProcessLock(
|
14092
|
+
constants.PipInstall.FINDLOCK
|
14093
|
+
)
|
13559
14094
|
try:
|
13560
|
-
|
13561
|
-
|
13562
|
-
self._xvfb_display = Display(visible=0, size=(width, height))
|
13563
|
-
self._xvfb_display.start()
|
13564
|
-
sb_config._virtual_display = self._xvfb_display
|
13565
|
-
self.headless_active = True
|
13566
|
-
sb_config.headless_active = True
|
14095
|
+
with pip_find_lock:
|
14096
|
+
pass
|
13567
14097
|
except Exception:
|
13568
|
-
|
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()
|
13569
14105
|
|
13570
14106
|
def __ad_block_as_needed(self):
|
13571
14107
|
"""This is an internal method for handling ad-blocking.
|
@@ -13787,12 +14323,10 @@ class BaseCase(unittest.TestCase):
|
|
13787
14323
|
selector, timeout=timeout, must_be_visible=True
|
13788
14324
|
)
|
13789
14325
|
if clear_first:
|
13790
|
-
|
14326
|
+
with suppress(Exception):
|
13791
14327
|
element.clear()
|
13792
14328
|
backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
|
13793
14329
|
element.send_keys(backspaces)
|
13794
|
-
except Exception:
|
13795
|
-
pass
|
13796
14330
|
text = self.__get_type_checked_text(text)
|
13797
14331
|
if not text.endswith("\n"):
|
13798
14332
|
element.send_keys(text)
|
@@ -13808,12 +14342,10 @@ class BaseCase(unittest.TestCase):
|
|
13808
14342
|
element = self.__get_shadow_element(
|
13809
14343
|
selector, timeout=timeout, must_be_visible=True
|
13810
14344
|
)
|
13811
|
-
|
14345
|
+
with suppress(Exception):
|
13812
14346
|
element.clear()
|
13813
14347
|
backspaces = Keys.BACK_SPACE * 42 # Autofill Defense
|
13814
14348
|
element.send_keys(backspaces)
|
13815
|
-
except Exception:
|
13816
|
-
pass
|
13817
14349
|
|
13818
14350
|
def __get_shadow_text(self, selector, timeout):
|
13819
14351
|
element = self.__get_shadow_element(
|
@@ -13933,19 +14465,13 @@ class BaseCase(unittest.TestCase):
|
|
13933
14465
|
a_t = SD.translate_assert_text(self._language)
|
13934
14466
|
i_n = SD.translate_in(self._language)
|
13935
14467
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
13936
|
-
a_t,
|
13937
|
-
text,
|
13938
|
-
i_n,
|
13939
|
-
by.upper(),
|
13940
|
-
selector,
|
14468
|
+
a_t, text, i_n, by.upper(), selector
|
13941
14469
|
)
|
13942
|
-
|
14470
|
+
with suppress(Exception):
|
13943
14471
|
js_utils.activate_jquery(self.driver)
|
13944
14472
|
js_utils.post_messenger_success_message(
|
13945
14473
|
self.driver, messenger_post, self.message_duration
|
13946
14474
|
)
|
13947
|
-
except Exception:
|
13948
|
-
pass
|
13949
14475
|
|
13950
14476
|
def __assert_exact_shadow_text_visible(self, text, selector, timeout):
|
13951
14477
|
self.__wait_for_exact_shadow_text_visible(text, selector, timeout)
|
@@ -13959,19 +14485,13 @@ class BaseCase(unittest.TestCase):
|
|
13959
14485
|
a_t = SD.translate_assert_exact_text(self._language)
|
13960
14486
|
i_n = SD.translate_in(self._language)
|
13961
14487
|
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
13962
|
-
a_t,
|
13963
|
-
text,
|
13964
|
-
i_n,
|
13965
|
-
by.upper(),
|
13966
|
-
selector,
|
14488
|
+
a_t, text, i_n, by.upper(), selector
|
13967
14489
|
)
|
13968
|
-
|
14490
|
+
with suppress(Exception):
|
13969
14491
|
js_utils.activate_jquery(self.driver)
|
13970
14492
|
js_utils.post_messenger_success_message(
|
13971
14493
|
self.driver, messenger_post, self.message_duration
|
13972
14494
|
)
|
13973
|
-
except Exception:
|
13974
|
-
pass
|
13975
14495
|
|
13976
14496
|
def __assert_non_empty_shadow_text_visible(self, selector, timeout, strip):
|
13977
14497
|
self.__wait_for_non_empty_shadow_text_visible(selector, timeout, strip)
|
@@ -13985,18 +14505,13 @@ class BaseCase(unittest.TestCase):
|
|
13985
14505
|
a_t = SD.translate_assert_non_empty_text(self._language)
|
13986
14506
|
i_n = SD.translate_in(self._language)
|
13987
14507
|
messenger_post = "<b>%s</b> %s %s: %s" % (
|
13988
|
-
a_t,
|
13989
|
-
i_n,
|
13990
|
-
by.upper(),
|
13991
|
-
selector,
|
14508
|
+
a_t, i_n, by.upper(), selector
|
13992
14509
|
)
|
13993
|
-
|
14510
|
+
with suppress(Exception):
|
13994
14511
|
js_utils.activate_jquery(self.driver)
|
13995
14512
|
js_utils.post_messenger_success_message(
|
13996
14513
|
self.driver, messenger_post, self.message_duration
|
13997
14514
|
)
|
13998
|
-
except Exception:
|
13999
|
-
pass
|
14000
14515
|
|
14001
14516
|
def __is_shadow_element_present(self, selector):
|
14002
14517
|
try:
|
@@ -14124,7 +14639,7 @@ class BaseCase(unittest.TestCase):
|
|
14124
14639
|
message = (
|
14125
14640
|
"Expected value {%s} for attribute {%s} of element "
|
14126
14641
|
"{%s} was not present after %s second%s! "
|
14127
|
-
"(
|
14642
|
+
"(Actual value was {%s})"
|
14128
14643
|
% (
|
14129
14644
|
value,
|
14130
14645
|
attribute,
|
@@ -14148,13 +14663,11 @@ class BaseCase(unittest.TestCase):
|
|
14148
14663
|
|
14149
14664
|
a_t = SD.translate_assert(self._language)
|
14150
14665
|
messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
|
14151
|
-
|
14666
|
+
with suppress(Exception):
|
14152
14667
|
js_utils.activate_jquery(self.driver)
|
14153
14668
|
js_utils.post_messenger_success_message(
|
14154
14669
|
self.driver, messenger_post, self.message_duration
|
14155
14670
|
)
|
14156
|
-
except Exception:
|
14157
|
-
pass
|
14158
14671
|
|
14159
14672
|
def __assert_shadow_element_visible(self, selector):
|
14160
14673
|
element = self.__get_shadow_element(selector)
|
@@ -14169,13 +14682,11 @@ class BaseCase(unittest.TestCase):
|
|
14169
14682
|
|
14170
14683
|
a_t = SD.translate_assert(self._language)
|
14171
14684
|
messenger_post = "<b>%s %s</b>: %s" % (a_t, by.upper(), selector)
|
14172
|
-
|
14685
|
+
with suppress(Exception):
|
14173
14686
|
js_utils.activate_jquery(self.driver)
|
14174
14687
|
js_utils.post_messenger_success_message(
|
14175
14688
|
self.driver, messenger_post, self.message_duration
|
14176
14689
|
)
|
14177
|
-
except Exception:
|
14178
|
-
pass
|
14179
14690
|
|
14180
14691
|
############
|
14181
14692
|
|
@@ -14250,10 +14761,15 @@ class BaseCase(unittest.TestCase):
|
|
14250
14761
|
self.env = self.environment # Add a shortened version
|
14251
14762
|
self.with_selenium = sb_config.with_selenium # Should be True
|
14252
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
|
14253
14768
|
self.headless_active = False
|
14254
14769
|
sb_config.headless_active = False
|
14255
14770
|
self.headed = sb_config.headed
|
14256
14771
|
self.xvfb = sb_config.xvfb
|
14772
|
+
self.xvfb_metrics = sb_config.xvfb_metrics
|
14257
14773
|
self.locale_code = sb_config.locale_code
|
14258
14774
|
self.interval = sb_config.interval
|
14259
14775
|
self.start_page = sb_config.start_page
|
@@ -14288,6 +14804,7 @@ class BaseCase(unittest.TestCase):
|
|
14288
14804
|
self.firefox_arg = sb_config.firefox_arg
|
14289
14805
|
self.firefox_pref = sb_config.firefox_pref
|
14290
14806
|
self.verify_delay = sb_config.verify_delay
|
14807
|
+
self.esc_end = sb_config.esc_end
|
14291
14808
|
self.recorder_mode = sb_config.recorder_mode
|
14292
14809
|
self.recorder_ext = sb_config.recorder_mode
|
14293
14810
|
self.rec_print = sb_config.rec_print
|
@@ -14302,6 +14819,7 @@ class BaseCase(unittest.TestCase):
|
|
14302
14819
|
elif self.record_sleep and not self.recorder_mode:
|
14303
14820
|
self.recorder_mode = True
|
14304
14821
|
self.recorder_ext = True
|
14822
|
+
self.disable_cookies = sb_config.disable_cookies
|
14305
14823
|
self.disable_js = sb_config.disable_js
|
14306
14824
|
self.disable_csp = sb_config.disable_csp
|
14307
14825
|
self.disable_ws = sb_config.disable_ws
|
@@ -14316,7 +14834,6 @@ class BaseCase(unittest.TestCase):
|
|
14316
14834
|
self.log_cdp_events = sb_config.log_cdp_events
|
14317
14835
|
self.no_sandbox = sb_config.no_sandbox
|
14318
14836
|
self.disable_gpu = sb_config.disable_gpu
|
14319
|
-
self.headless2 = sb_config.headless2
|
14320
14837
|
self.incognito = sb_config.incognito
|
14321
14838
|
self.guest_mode = sb_config.guest_mode
|
14322
14839
|
self.dark_mode = sb_config.dark_mode
|
@@ -14344,31 +14861,8 @@ class BaseCase(unittest.TestCase):
|
|
14344
14861
|
self.use_wire = sb_config.use_wire
|
14345
14862
|
self.external_pdf = sb_config.external_pdf
|
14346
14863
|
self._final_debug = sb_config.final_debug
|
14864
|
+
self.window_position = sb_config.window_position
|
14347
14865
|
self.window_size = sb_config.window_size
|
14348
|
-
window_size = self.window_size
|
14349
|
-
if window_size:
|
14350
|
-
if window_size.count(",") != 1:
|
14351
|
-
message = (
|
14352
|
-
'\n\n window_size expects a "width,height" string!'
|
14353
|
-
'\n (Your input was: "%s")\n' % window_size
|
14354
|
-
)
|
14355
|
-
raise Exception(message)
|
14356
|
-
window_size = window_size.replace(" ", "")
|
14357
|
-
width = None
|
14358
|
-
height = None
|
14359
|
-
try:
|
14360
|
-
width = int(window_size.split(",")[0])
|
14361
|
-
height = int(window_size.split(",")[1])
|
14362
|
-
except Exception:
|
14363
|
-
message = (
|
14364
|
-
'\n\n Expecting integer values for "width,height"!'
|
14365
|
-
'\n (window_size input was: "%s")\n' % window_size
|
14366
|
-
)
|
14367
|
-
raise Exception(message)
|
14368
|
-
settings.CHROME_START_WIDTH = width
|
14369
|
-
settings.CHROME_START_HEIGHT = height
|
14370
|
-
settings.HEADLESS_START_WIDTH = width
|
14371
|
-
settings.HEADLESS_START_HEIGHT = height
|
14372
14866
|
self.maximize_option = sb_config.maximize_option
|
14373
14867
|
self.save_screenshot_after_test = sb_config.save_screenshot
|
14374
14868
|
self.no_screenshot_after_test = sb_config.no_screenshot
|
@@ -14426,15 +14920,13 @@ class BaseCase(unittest.TestCase):
|
|
14426
14920
|
self.__skip_reason = None
|
14427
14921
|
self.testcase_manager.insert_testcase_data(data_payload)
|
14428
14922
|
self.case_start_time = int(time.time() * 1000.0)
|
14429
|
-
self.__activate_virtual_display_as_needed()
|
14430
14923
|
elif hasattr(self, "is_behave") and self.is_behave:
|
14431
14924
|
self.__initialize_variables()
|
14432
|
-
self.__activate_virtual_display_as_needed()
|
14433
14925
|
elif hasattr(self, "is_nosetest") and self.is_nosetest:
|
14434
14926
|
pass # Setup performed in plugins for pynose
|
14435
14927
|
else:
|
14436
|
-
# Pure Python run. Eg. SB()
|
14437
|
-
|
14928
|
+
# Pure Python run. (Eg. SB() and Driver() Managers)
|
14929
|
+
pass # Variables initialized in respective plugins
|
14438
14930
|
|
14439
14931
|
# Verify SeleniumBase is installed successfully, and used correctly
|
14440
14932
|
if not hasattr(self, "browser"):
|
@@ -14519,8 +15011,8 @@ class BaseCase(unittest.TestCase):
|
|
14519
15011
|
metrics_list = metrics_string.split(",")
|
14520
15012
|
exception_string = (
|
14521
15013
|
"Invalid input for Mobile Emulator device metrics!\n"
|
14522
|
-
"Expecting a comma-separated string with
|
14523
|
-
"
|
15014
|
+
"Expecting a comma-separated string with integer values\n"
|
15015
|
+
"for Width/Height, and an int or float for Pixel-Ratio.\n"
|
14524
15016
|
'Example: --metrics="411,731,3" '
|
14525
15017
|
)
|
14526
15018
|
if len(metrics_list) != 3:
|
@@ -14528,13 +15020,91 @@ class BaseCase(unittest.TestCase):
|
|
14528
15020
|
try:
|
14529
15021
|
self.__device_width = int(metrics_list[0])
|
14530
15022
|
self.__device_height = int(metrics_list[1])
|
14531
|
-
self.__device_pixel_ratio =
|
15023
|
+
self.__device_pixel_ratio = float(metrics_list[2])
|
14532
15024
|
self.mobile_emulator = True
|
14533
15025
|
except Exception:
|
14534
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
|
+
|
14535
15104
|
if self.mobile_emulator and not self.user_agent:
|
14536
15105
|
# Use a Pixel user agent by default if not specified
|
14537
15106
|
self.user_agent = constants.Mobile.AGENT
|
15107
|
+
|
14538
15108
|
if self.browser in ["firefox", "ie", "safari"]:
|
14539
15109
|
# The Recorder Mode browser extension is only for Chrome/Edge.
|
14540
15110
|
if self.recorder_mode:
|
@@ -14544,10 +15114,18 @@ class BaseCase(unittest.TestCase):
|
|
14544
15114
|
)
|
14545
15115
|
raise Exception(message)
|
14546
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
|
+
|
14547
15121
|
# Dashboard pre-processing:
|
14548
15122
|
if self.dashboard:
|
14549
15123
|
if self._multithreaded:
|
14550
15124
|
with self.dash_lock:
|
15125
|
+
with suppress(Exception):
|
15126
|
+
shared_utils.make_writable(
|
15127
|
+
constants.Dashboard.LOCKFILE
|
15128
|
+
)
|
14551
15129
|
if not self._dash_initialized:
|
14552
15130
|
sb_config._dashboard_initialized = True
|
14553
15131
|
self._dash_initialized = True
|
@@ -14568,7 +15146,7 @@ class BaseCase(unittest.TestCase):
|
|
14568
15146
|
if not hasattr(sb_config, "shared_driver"):
|
14569
15147
|
sb_config.shared_driver = None
|
14570
15148
|
if sb_config.shared_driver:
|
14571
|
-
|
15149
|
+
with suppress(Exception):
|
14572
15150
|
self._default_driver = sb_config.shared_driver
|
14573
15151
|
self.driver = sb_config.shared_driver
|
14574
15152
|
self._drivers_list = [sb_config.shared_driver]
|
@@ -14582,12 +15160,8 @@ class BaseCase(unittest.TestCase):
|
|
14582
15160
|
self.switch_to_window(0)
|
14583
15161
|
if self._crumbs:
|
14584
15162
|
self.wait_for_ready_state_complete()
|
14585
|
-
|
15163
|
+
with suppress(Exception):
|
14586
15164
|
self.driver.delete_all_cookies()
|
14587
|
-
except Exception:
|
14588
|
-
pass
|
14589
|
-
except Exception:
|
14590
|
-
pass
|
14591
15165
|
if self._reuse_session and sb_config.shared_driver and has_url:
|
14592
15166
|
good_start_page = False
|
14593
15167
|
if self.recorder_ext:
|
@@ -14630,6 +15204,7 @@ class BaseCase(unittest.TestCase):
|
|
14630
15204
|
cap_file=self.cap_file,
|
14631
15205
|
cap_string=self.cap_string,
|
14632
15206
|
recorder_ext=self.recorder_ext,
|
15207
|
+
disable_cookies=self.disable_cookies,
|
14633
15208
|
disable_js=self.disable_js,
|
14634
15209
|
disable_csp=self.disable_csp,
|
14635
15210
|
enable_ws=self.enable_ws,
|
@@ -14641,6 +15216,7 @@ class BaseCase(unittest.TestCase):
|
|
14641
15216
|
log_cdp_events=self.log_cdp_events,
|
14642
15217
|
no_sandbox=self.no_sandbox,
|
14643
15218
|
disable_gpu=self.disable_gpu,
|
15219
|
+
headless1=self.headless1,
|
14644
15220
|
headless2=self.headless2,
|
14645
15221
|
incognito=self.incognito,
|
14646
15222
|
guest_mode=self.guest_mode,
|
@@ -14674,10 +15250,8 @@ class BaseCase(unittest.TestCase):
|
|
14674
15250
|
if self.driver.timeouts.implicit_wait > 0:
|
14675
15251
|
self.driver.implicitly_wait(0)
|
14676
15252
|
except Exception:
|
14677
|
-
|
15253
|
+
with suppress(Exception):
|
14678
15254
|
self.driver.implicitly_wait(0)
|
14679
|
-
except Exception:
|
14680
|
-
pass
|
14681
15255
|
self._default_driver = self.driver
|
14682
15256
|
if self._reuse_session:
|
14683
15257
|
sb_config.shared_driver = self.driver
|
@@ -14696,13 +15270,11 @@ class BaseCase(unittest.TestCase):
|
|
14696
15270
|
self.set_time_limit(self.time_limit)
|
14697
15271
|
|
14698
15272
|
# Configure the page load timeout
|
14699
|
-
|
15273
|
+
with suppress(Exception):
|
14700
15274
|
if hasattr(settings, "PAGE_LOAD_TIMEOUT"):
|
14701
15275
|
self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT)
|
14702
15276
|
else:
|
14703
15277
|
self.driver.set_page_load_timeout(120) # Selenium uses 300
|
14704
|
-
except Exception:
|
14705
|
-
pass
|
14706
15278
|
|
14707
15279
|
# Set the start time for the test (in ms).
|
14708
15280
|
# Although the pytest clock starts before setUp() begins,
|
@@ -14731,7 +15303,7 @@ class BaseCase(unittest.TestCase):
|
|
14731
15303
|
not self.__last_page_screenshot
|
14732
15304
|
and not self.__last_page_screenshot_png
|
14733
15305
|
):
|
14734
|
-
|
15306
|
+
with suppress(Exception):
|
14735
15307
|
try:
|
14736
15308
|
element = page_actions.wait_for_element_visible(
|
14737
15309
|
self.driver,
|
@@ -14761,14 +15333,10 @@ class BaseCase(unittest.TestCase):
|
|
14761
15333
|
element.screenshot_as_base64
|
14762
15334
|
)
|
14763
15335
|
except Exception:
|
14764
|
-
|
15336
|
+
with suppress(Exception):
|
14765
15337
|
self.__last_page_screenshot = (
|
14766
15338
|
self.driver.get_screenshot_as_base64()
|
14767
15339
|
)
|
14768
|
-
except Exception:
|
14769
|
-
pass
|
14770
|
-
except Exception:
|
14771
|
-
pass
|
14772
15340
|
if not self.__last_page_screenshot:
|
14773
15341
|
self.__last_page_screenshot = SCREENSHOT_UNDEFINED
|
14774
15342
|
self.__last_page_screenshot_png = SCREENSHOT_UNDEFINED
|
@@ -14778,12 +15346,10 @@ class BaseCase(unittest.TestCase):
|
|
14778
15346
|
element.screenshot_as_png
|
14779
15347
|
)
|
14780
15348
|
except Exception:
|
14781
|
-
|
15349
|
+
with suppress(Exception):
|
14782
15350
|
self.__last_page_screenshot_png = (
|
14783
15351
|
self.driver.get_screenshot_as_png()
|
14784
15352
|
)
|
14785
|
-
except Exception:
|
14786
|
-
pass
|
14787
15353
|
else:
|
14788
15354
|
import base64
|
14789
15355
|
|
@@ -14798,12 +15364,10 @@ class BaseCase(unittest.TestCase):
|
|
14798
15364
|
element.screenshot_as_png
|
14799
15365
|
)
|
14800
15366
|
except Exception:
|
14801
|
-
|
15367
|
+
with suppress(Exception):
|
14802
15368
|
self.__last_page_screenshot_png = (
|
14803
15369
|
self.driver.get_screenshot_as_png()
|
14804
15370
|
)
|
14805
|
-
except Exception:
|
14806
|
-
pass
|
14807
15371
|
sb_config._last_page_screenshot_png = self.__last_page_screenshot_png
|
14808
15372
|
|
14809
15373
|
def __set_last_page_url(self):
|
@@ -14855,7 +15419,6 @@ class BaseCase(unittest.TestCase):
|
|
14855
15419
|
data_payload.state = state
|
14856
15420
|
if err:
|
14857
15421
|
import traceback
|
14858
|
-
|
14859
15422
|
tb_string = traceback.format_exc()
|
14860
15423
|
if "Message: " in tb_string:
|
14861
15424
|
data_payload.message = (
|
@@ -14890,7 +15453,7 @@ class BaseCase(unittest.TestCase):
|
|
14890
15453
|
|
14891
15454
|
def __add_pytest_html_extra(self):
|
14892
15455
|
if not self.__added_pytest_html_extra:
|
14893
|
-
|
15456
|
+
with suppress(Exception):
|
14894
15457
|
if self.with_selenium:
|
14895
15458
|
if not self.__last_page_screenshot:
|
14896
15459
|
self.__set_last_page_screenshot()
|
@@ -14917,8 +15480,6 @@ class BaseCase(unittest.TestCase):
|
|
14917
15480
|
):
|
14918
15481
|
self._html_report_extra.append(extra_url)
|
14919
15482
|
self._html_report_extra.append(extra_image)
|
14920
|
-
except Exception:
|
14921
|
-
pass
|
14922
15483
|
|
14923
15484
|
def __delay_driver_quit(self):
|
14924
15485
|
delay_driver_quit = False
|
@@ -15012,7 +15573,6 @@ class BaseCase(unittest.TestCase):
|
|
15012
15573
|
context_id = None
|
15013
15574
|
if filename == "base_case.py" or methodname == "runTest":
|
15014
15575
|
import traceback
|
15015
|
-
|
15016
15576
|
stack_base = traceback.format_stack()[0].split(", in ")[0]
|
15017
15577
|
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
|
15018
15578
|
if hasattr(self, "cm_filename") and self.cm_filename:
|
@@ -15032,7 +15592,8 @@ class BaseCase(unittest.TestCase):
|
|
15032
15592
|
elif hasattr(self, "_using_sb_fixture") and self._using_sb_fixture:
|
15033
15593
|
test_id = sb_config._latest_display_id
|
15034
15594
|
test_id = test_id.replace(".py::", ".").replace("::", ".")
|
15035
|
-
test_id = test_id.replace("/", ".").replace("
|
15595
|
+
test_id = test_id.replace("/", ".").replace("\\", ".")
|
15596
|
+
test_id = test_id.replace(" ", "_")
|
15036
15597
|
# Linux filename length limit for `codecs.open(filename)` = 255
|
15037
15598
|
# 255 - len("latest_logs/") - len("/basic_test_info.txt") = 223
|
15038
15599
|
if len(test_id) <= 223:
|
@@ -15124,6 +15685,8 @@ class BaseCase(unittest.TestCase):
|
|
15124
15685
|
constants.Dashboard.LOCKFILE
|
15125
15686
|
)
|
15126
15687
|
with self.dash_lock:
|
15688
|
+
with suppress(Exception):
|
15689
|
+
shared_utils.make_writable(constants.Dashboard.LOCKFILE)
|
15127
15690
|
self.__process_dashboard(has_exception, init)
|
15128
15691
|
else:
|
15129
15692
|
self.__process_dashboard(has_exception, init)
|
@@ -15607,6 +16170,31 @@ class BaseCase(unittest.TestCase):
|
|
15607
16170
|
else:
|
15608
16171
|
return None
|
15609
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
|
+
|
15610
16198
|
def _addSkip(self, result, test_case, reason):
|
15611
16199
|
"""This method should NOT be called directly from tests."""
|
15612
16200
|
addSkip = getattr(result, 'addSkip', None)
|
@@ -15704,7 +16292,15 @@ class BaseCase(unittest.TestCase):
|
|
15704
16292
|
# This test already called tearDown()
|
15705
16293
|
return
|
15706
16294
|
if hasattr(self, "recorder_mode") and self.recorder_mode:
|
15707
|
-
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)
|
15708
16304
|
self.__called_teardown = True
|
15709
16305
|
self.__called_setup = False
|
15710
16306
|
try:
|
@@ -15737,6 +16333,7 @@ class BaseCase(unittest.TestCase):
|
|
15737
16333
|
)
|
15738
16334
|
raise Exception(message)
|
15739
16335
|
# *** Start tearDown() officially ***
|
16336
|
+
page_actions._reconnect_if_disconnected(self.driver)
|
15740
16337
|
self.__slow_mode_pause_if_active()
|
15741
16338
|
has_exception = self.__has_exception()
|
15742
16339
|
sb_config._has_exception = has_exception
|
@@ -15859,6 +16456,10 @@ class BaseCase(unittest.TestCase):
|
|
15859
16456
|
if self.dashboard:
|
15860
16457
|
if self._multithreaded:
|
15861
16458
|
with self.dash_lock:
|
16459
|
+
with suppress(Exception):
|
16460
|
+
shared_utils.make_writable(
|
16461
|
+
constants.Dashboard.LOCKFILE
|
16462
|
+
)
|
15862
16463
|
self.__process_dashboard(has_exception)
|
15863
16464
|
else:
|
15864
16465
|
self.__process_dashboard(has_exception)
|
@@ -15926,7 +16527,6 @@ class BaseCase(unittest.TestCase):
|
|
15926
16527
|
else:
|
15927
16528
|
# (Pynose / Behave / Pure Python)
|
15928
16529
|
if hasattr(self, "is_behave") and self.is_behave:
|
15929
|
-
import colorama
|
15930
16530
|
if sb_config.behave_scenario.status.name == "failed":
|
15931
16531
|
has_exception = True
|
15932
16532
|
sb_config._has_exception = True
|
@@ -15934,8 +16534,6 @@ class BaseCase(unittest.TestCase):
|
|
15934
16534
|
if is_windows:
|
15935
16535
|
c1 = colorama.Fore.RED + colorama.Back.LIGHTRED_EX
|
15936
16536
|
cr = colorama.Style.RESET_ALL
|
15937
|
-
if hasattr(colorama, "just_fix_windows_console"):
|
15938
|
-
colorama.just_fix_windows_console()
|
15939
16537
|
msg = msg.replace("❌", c1 + "><" + cr)
|
15940
16538
|
print(msg)
|
15941
16539
|
else:
|
@@ -15943,8 +16541,6 @@ class BaseCase(unittest.TestCase):
|
|
15943
16541
|
if is_windows:
|
15944
16542
|
c2 = colorama.Fore.GREEN + colorama.Back.LIGHTGREEN_EX
|
15945
16543
|
cr = colorama.Style.RESET_ALL
|
15946
|
-
if hasattr(colorama, "just_fix_windows_console"):
|
15947
|
-
colorama.just_fix_windows_console()
|
15948
16544
|
msg = msg.replace("✅", c2 + "<>" + cr)
|
15949
16545
|
print(msg)
|
15950
16546
|
if self.dashboard:
|
@@ -16009,6 +16605,7 @@ class BaseCase(unittest.TestCase):
|
|
16009
16605
|
self.__quit_all_drivers()
|
16010
16606
|
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
|
16011
16607
|
if hasattr(self, "_xvfb_display") and self._xvfb_display:
|
16608
|
+
# Stop the Xvfb virtual display launched from BaseCase
|
16012
16609
|
try:
|
16013
16610
|
if hasattr(self._xvfb_display, "stop"):
|
16014
16611
|
self._xvfb_display.stop()
|
@@ -16018,6 +16615,20 @@ class BaseCase(unittest.TestCase):
|
|
16018
16615
|
pass
|
16019
16616
|
except Exception:
|
16020
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
|
16021
16632
|
if self.__visual_baseline_copies:
|
16022
16633
|
sb_config._visual_baseline_copies = True
|
16023
16634
|
if has_exception:
|