seleniumbase 4.24.11__py3-none-any.whl → 4.33.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sbase/__init__.py +1 -0
- sbase/steps.py +7 -0
- seleniumbase/__init__.py +16 -7
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +97 -32
- seleniumbase/common/decorators.py +16 -7
- seleniumbase/config/proxy_list.py +3 -3
- seleniumbase/config/settings.py +4 -0
- seleniumbase/console_scripts/logo_helper.py +47 -8
- seleniumbase/console_scripts/run.py +345 -335
- seleniumbase/console_scripts/sb_behave_gui.py +5 -12
- seleniumbase/console_scripts/sb_caseplans.py +6 -13
- seleniumbase/console_scripts/sb_commander.py +5 -12
- seleniumbase/console_scripts/sb_install.py +62 -54
- seleniumbase/console_scripts/sb_mkchart.py +13 -20
- seleniumbase/console_scripts/sb_mkdir.py +11 -17
- seleniumbase/console_scripts/sb_mkfile.py +69 -43
- seleniumbase/console_scripts/sb_mkpres.py +13 -20
- seleniumbase/console_scripts/sb_mkrec.py +88 -21
- seleniumbase/console_scripts/sb_objectify.py +30 -30
- seleniumbase/console_scripts/sb_print.py +5 -12
- seleniumbase/console_scripts/sb_recorder.py +16 -11
- seleniumbase/core/browser_launcher.py +1658 -221
- seleniumbase/core/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:
|