seleniumbase 4.44.2__py3-none-any.whl → 4.45.10__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.
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +14 -0
- seleniumbase/console_scripts/run.py +1 -0
- seleniumbase/console_scripts/sb_install.py +142 -11
- seleniumbase/console_scripts/sb_mkdir.py +76 -0
- seleniumbase/console_scripts/sb_mkrec.py +25 -0
- seleniumbase/console_scripts/sb_recorder.py +40 -3
- seleniumbase/core/browser_launcher.py +279 -117
- seleniumbase/core/detect_b_ver.py +8 -6
- seleniumbase/core/log_helper.py +11 -16
- seleniumbase/core/mysql.py +1 -1
- seleniumbase/core/report_helper.py +3 -7
- seleniumbase/core/sb_cdp.py +275 -78
- seleniumbase/core/sb_driver.py +36 -5
- seleniumbase/core/session_helper.py +2 -4
- seleniumbase/drivers/chromium_drivers/__init__.py +0 -0
- seleniumbase/fixtures/base_case.py +251 -201
- seleniumbase/fixtures/constants.py +1 -0
- seleniumbase/fixtures/js_utils.py +52 -14
- seleniumbase/fixtures/page_actions.py +18 -7
- seleniumbase/fixtures/page_utils.py +4 -2
- seleniumbase/fixtures/shared_utils.py +2 -4
- seleniumbase/masterqa/master_qa.py +16 -2
- seleniumbase/plugins/base_plugin.py +8 -0
- seleniumbase/plugins/driver_manager.py +15 -5
- seleniumbase/plugins/pytest_plugin.py +43 -57
- seleniumbase/plugins/sb_manager.py +23 -19
- seleniumbase/plugins/selenium_plugin.py +20 -13
- seleniumbase/undetected/__init__.py +11 -10
- seleniumbase/undetected/cdp.py +1 -12
- seleniumbase/undetected/cdp_driver/browser.py +330 -128
- seleniumbase/undetected/cdp_driver/cdp_util.py +48 -14
- seleniumbase/undetected/cdp_driver/config.py +78 -11
- seleniumbase/undetected/cdp_driver/connection.py +15 -43
- seleniumbase/undetected/cdp_driver/element.py +37 -22
- seleniumbase/undetected/cdp_driver/tab.py +414 -39
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/METADATA +140 -152
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/RECORD +42 -41
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/licenses/LICENSE +1 -1
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/WHEEL +0 -0
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.44.2.dist-info → seleniumbase-4.45.10.dist-info}/top_level.txt +0 -0
|
@@ -221,11 +221,28 @@ class BaseCase(unittest.TestCase):
|
|
|
221
221
|
[sys.executable, "-m", "pytest", file, "-s", *all_args]
|
|
222
222
|
)
|
|
223
223
|
|
|
224
|
-
def open(self, url):
|
|
224
|
+
def open(self, url, **kwargs):
|
|
225
225
|
"""Navigates the current browser window to the specified page."""
|
|
226
226
|
self.__check_scope()
|
|
227
227
|
if self.__is_cdp_swap_needed():
|
|
228
|
-
self.cdp.open(url)
|
|
228
|
+
self.cdp.open(url, **kwargs)
|
|
229
|
+
return
|
|
230
|
+
elif (
|
|
231
|
+
getattr(self.driver, "_is_using_uc", None)
|
|
232
|
+
# and getattr(self.driver, "_is_using_auth", None)
|
|
233
|
+
and not getattr(self.driver, "_is_using_cdp", None)
|
|
234
|
+
):
|
|
235
|
+
# Auth in UC Mode requires CDP Mode
|
|
236
|
+
# (and now we're always forcing it)
|
|
237
|
+
logging.info("open() in UC Mode now always activates CDP Mode.")
|
|
238
|
+
self.activate_cdp_mode(url, **kwargs)
|
|
239
|
+
return
|
|
240
|
+
elif (
|
|
241
|
+
getattr(self.driver, "_is_using_uc", None)
|
|
242
|
+
and getattr(self.driver, "_is_using_cdp", None)
|
|
243
|
+
):
|
|
244
|
+
self.disconnect()
|
|
245
|
+
self.cdp.open(url, **kwargs)
|
|
229
246
|
return
|
|
230
247
|
self._check_browser()
|
|
231
248
|
if self.__needs_minimum_wait():
|
|
@@ -1293,8 +1310,11 @@ class BaseCase(unittest.TestCase):
|
|
|
1293
1310
|
self.__check_scope()
|
|
1294
1311
|
return self.execute_script("return window.location.origin;")
|
|
1295
1312
|
|
|
1296
|
-
def
|
|
1297
|
-
|
|
1313
|
+
def get_html(self, *args, **kwargs):
|
|
1314
|
+
return self.get_page_source(*args, **kwargs)
|
|
1315
|
+
|
|
1316
|
+
def get_page_source(self, *args, **kwargs):
|
|
1317
|
+
if self.__is_cdp_swap_needed(*args, **kwargs):
|
|
1298
1318
|
return self.cdp.get_page_source()
|
|
1299
1319
|
self.wait_for_ready_state_complete()
|
|
1300
1320
|
if self.__needs_minimum_wait:
|
|
@@ -1333,7 +1353,7 @@ class BaseCase(unittest.TestCase):
|
|
|
1333
1353
|
if self.__is_cdp_swap_needed():
|
|
1334
1354
|
self.cdp.go_back()
|
|
1335
1355
|
return
|
|
1336
|
-
if
|
|
1356
|
+
if getattr(self, "recorder_mode", None):
|
|
1337
1357
|
self.save_recorded_actions()
|
|
1338
1358
|
pre_action_url = None
|
|
1339
1359
|
with suppress(Exception):
|
|
@@ -1361,7 +1381,7 @@ class BaseCase(unittest.TestCase):
|
|
|
1361
1381
|
if self.__is_cdp_swap_needed():
|
|
1362
1382
|
self.cdp.go_forward()
|
|
1363
1383
|
return
|
|
1364
|
-
if
|
|
1384
|
+
if getattr(self, "recorder_mode", None):
|
|
1365
1385
|
self.save_recorded_actions()
|
|
1366
1386
|
self.__last_page_load_url = None
|
|
1367
1387
|
self.driver.forward()
|
|
@@ -1617,14 +1637,14 @@ class BaseCase(unittest.TestCase):
|
|
|
1617
1637
|
def click_link_text(self, link_text, timeout=None):
|
|
1618
1638
|
"""This method clicks link text on a page."""
|
|
1619
1639
|
self.__check_scope()
|
|
1620
|
-
if self.__is_cdp_swap_needed():
|
|
1621
|
-
self.cdp.find_element(link_text, timeout=timeout).click()
|
|
1622
|
-
return
|
|
1623
|
-
self.__skip_if_esc()
|
|
1624
1640
|
if not timeout:
|
|
1625
1641
|
timeout = settings.SMALL_TIMEOUT
|
|
1626
1642
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
1627
1643
|
timeout = self.__get_new_timeout(timeout)
|
|
1644
|
+
if self.__is_cdp_swap_needed():
|
|
1645
|
+
self.cdp.find_element(link_text, timeout=timeout).click()
|
|
1646
|
+
return
|
|
1647
|
+
self.__skip_if_esc()
|
|
1628
1648
|
link_text = self.__get_type_checked_text(link_text)
|
|
1629
1649
|
if self.__is_cdp_swap_needed():
|
|
1630
1650
|
self.cdp.click_link(link_text)
|
|
@@ -2697,7 +2717,7 @@ class BaseCase(unittest.TestCase):
|
|
|
2697
2717
|
original_by = by
|
|
2698
2718
|
selector, by = self.__recalculate_selector(selector, by)
|
|
2699
2719
|
if self.__is_cdp_swap_needed():
|
|
2700
|
-
self.cdp.
|
|
2720
|
+
self.cdp.hover_element(selector)
|
|
2701
2721
|
return
|
|
2702
2722
|
self.wait_for_element_visible(
|
|
2703
2723
|
original_selector, by=original_by, timeout=timeout
|
|
@@ -2742,7 +2762,7 @@ class BaseCase(unittest.TestCase):
|
|
|
2742
2762
|
click_selector, click_by
|
|
2743
2763
|
)
|
|
2744
2764
|
if self.__is_cdp_swap_needed():
|
|
2745
|
-
self.cdp.
|
|
2765
|
+
self.cdp.hover_and_click(hover_selector, click_selector)
|
|
2746
2766
|
return
|
|
2747
2767
|
dropdown_element = self.wait_for_element_visible(
|
|
2748
2768
|
original_selector, by=original_by, timeout=timeout
|
|
@@ -3426,6 +3446,46 @@ class BaseCase(unittest.TestCase):
|
|
|
3426
3446
|
file_path = os.path.join(abs_path, html_file)
|
|
3427
3447
|
self.open("file://" + file_path)
|
|
3428
3448
|
|
|
3449
|
+
def evaluate(self, expression):
|
|
3450
|
+
"""Run a JavaScript expression and return the result."""
|
|
3451
|
+
self.__check_scope()
|
|
3452
|
+
if self.__is_cdp_swap_needed():
|
|
3453
|
+
return self.cdp.evaluate(expression)
|
|
3454
|
+
self._check_browser()
|
|
3455
|
+
original_expression = expression
|
|
3456
|
+
expression = expression.strip()
|
|
3457
|
+
exp_list = expression.split("\n")
|
|
3458
|
+
if exp_list and exp_list[-1].strip().startswith("return "):
|
|
3459
|
+
expression = (
|
|
3460
|
+
"\n".join(exp_list[0:-1]) + "\n"
|
|
3461
|
+
+ exp_list[-1].strip()[len("return "):]
|
|
3462
|
+
).strip()
|
|
3463
|
+
evaluation = self.driver.execute_cdp_cmd(
|
|
3464
|
+
"Runtime.evaluate",
|
|
3465
|
+
{
|
|
3466
|
+
"expression": expression
|
|
3467
|
+
},
|
|
3468
|
+
)
|
|
3469
|
+
if "value" in evaluation["result"]:
|
|
3470
|
+
return evaluation["result"]["value"]
|
|
3471
|
+
elif evaluation["result"]["type"] == "undefined":
|
|
3472
|
+
return None
|
|
3473
|
+
elif "exceptionDetails" in evaluation:
|
|
3474
|
+
raise Exception(evaluation["result"]["description"], expression)
|
|
3475
|
+
elif evaluation["result"]["type"] == "object":
|
|
3476
|
+
if "return " not in original_expression:
|
|
3477
|
+
expression = "return " + original_expression.strip()
|
|
3478
|
+
# Need to use execute_script() to return a WebDriver object.
|
|
3479
|
+
# If this causes duplicate evaluation, don't use evaluate().
|
|
3480
|
+
return self.execute_script(expression)
|
|
3481
|
+
elif evaluation["result"]["type"] == "function":
|
|
3482
|
+
return {} # This is what sb.cdp.evaluate returns
|
|
3483
|
+
elif "description" in evaluation["result"]:
|
|
3484
|
+
# At this point, the description is the exception
|
|
3485
|
+
raise Exception(evaluation["result"]["description"], expression)
|
|
3486
|
+
else: # Possibly an unhandled case if reached
|
|
3487
|
+
return None
|
|
3488
|
+
|
|
3429
3489
|
def execute_script(self, script, *args, **kwargs):
|
|
3430
3490
|
self.__check_scope()
|
|
3431
3491
|
if self.__is_cdp_swap_needed():
|
|
@@ -3940,10 +4000,23 @@ class BaseCase(unittest.TestCase):
|
|
|
3940
4000
|
Reverts self.set_content_to_frame()."""
|
|
3941
4001
|
self.set_content_to_default(nested=True)
|
|
3942
4002
|
|
|
3943
|
-
def open_new_window(self, switch_to=True):
|
|
4003
|
+
def open_new_window(self, switch_to=True, **kwargs):
|
|
3944
4004
|
"""Opens a new browser tab/window and switches to it by default."""
|
|
4005
|
+
url = None
|
|
4006
|
+
if self.__looks_like_a_page_url(str(switch_to)):
|
|
4007
|
+
# Different API for CDP Mode: First arg is a `url`.
|
|
4008
|
+
# (Also, don't break backwards compat for reg mode)
|
|
4009
|
+
url = switch_to
|
|
4010
|
+
switch_to = True
|
|
3945
4011
|
if self.__is_cdp_swap_needed():
|
|
3946
|
-
self.cdp.open_new_tab(switch_to=switch_to)
|
|
4012
|
+
self.cdp.open_new_tab(url=url, switch_to=switch_to, **kwargs)
|
|
4013
|
+
return
|
|
4014
|
+
elif (
|
|
4015
|
+
getattr(self.driver, "_is_using_uc", None)
|
|
4016
|
+
and getattr(self.driver, "_is_using_cdp", None)
|
|
4017
|
+
):
|
|
4018
|
+
self.disconnect()
|
|
4019
|
+
self.cdp.open_new_tab(url=url, switch_to=switch_to, **kwargs)
|
|
3947
4020
|
return
|
|
3948
4021
|
self.wait_for_ready_state_complete()
|
|
3949
4022
|
if switch_to:
|
|
@@ -4694,7 +4767,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4694
4767
|
if not os.path.exists(file_path):
|
|
4695
4768
|
os.makedirs(file_path)
|
|
4696
4769
|
cookies_file_path = os.path.join(file_path, name)
|
|
4697
|
-
cookies_file = open(cookies_file_path, "w+", encoding="utf-8")
|
|
4770
|
+
cookies_file = open(cookies_file_path, mode="w+", encoding="utf-8")
|
|
4698
4771
|
cookies_file.writelines(json_cookies)
|
|
4699
4772
|
cookies_file.close()
|
|
4700
4773
|
|
|
@@ -4853,7 +4926,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4853
4926
|
self.driver.add_cookie(cookie)
|
|
4854
4927
|
|
|
4855
4928
|
def __set_esc_skip(self):
|
|
4856
|
-
if
|
|
4929
|
+
if getattr(self, "esc_end", None):
|
|
4857
4930
|
script = (
|
|
4858
4931
|
"""document.onkeydown = function(evt) {
|
|
4859
4932
|
evt = evt || window.event;
|
|
@@ -4871,7 +4944,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4871
4944
|
self.execute_script(script)
|
|
4872
4945
|
|
|
4873
4946
|
def __skip_if_esc(self):
|
|
4874
|
-
if
|
|
4947
|
+
if getattr(self, "esc_end", None):
|
|
4875
4948
|
if self.execute_script("return document.sb_esc_end;") == "yes":
|
|
4876
4949
|
self.skip()
|
|
4877
4950
|
|
|
@@ -4893,8 +4966,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4893
4966
|
self.__disable_beforeunload_as_needed()
|
|
4894
4967
|
if (
|
|
4895
4968
|
self.page_load_strategy == "none"
|
|
4896
|
-
and
|
|
4897
|
-
and settings.SKIP_JS_WAITS
|
|
4969
|
+
and getattr(settings, "SKIP_JS_WAITS", None)
|
|
4898
4970
|
):
|
|
4899
4971
|
time.sleep(0.01)
|
|
4900
4972
|
if self.undetectable:
|
|
@@ -4915,10 +4987,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4915
4987
|
|
|
4916
4988
|
def sleep(self, seconds):
|
|
4917
4989
|
self.__check_scope()
|
|
4918
|
-
if (
|
|
4919
|
-
not hasattr(sb_config, "time_limit")
|
|
4920
|
-
or (hasattr(sb_config, "time_limit") and not sb_config.time_limit)
|
|
4921
|
-
):
|
|
4990
|
+
if not getattr(sb_config, "time_limit", None):
|
|
4922
4991
|
time.sleep(seconds)
|
|
4923
4992
|
elif seconds < 0.4:
|
|
4924
4993
|
shared_utils.check_if_time_limit_exceeded()
|
|
@@ -4933,11 +5002,7 @@ class BaseCase(unittest.TestCase):
|
|
|
4933
5002
|
if now_ms >= stop_ms:
|
|
4934
5003
|
break
|
|
4935
5004
|
time.sleep(0.2)
|
|
4936
|
-
if (
|
|
4937
|
-
self.recorder_mode
|
|
4938
|
-
and hasattr(sb_config, "record_sleep")
|
|
4939
|
-
and sb_config.record_sleep
|
|
4940
|
-
):
|
|
5005
|
+
if self.recorder_mode and getattr(sb_config, "record_sleep", None):
|
|
4941
5006
|
time_stamp = self.execute_script("return Date.now();")
|
|
4942
5007
|
origin = self.get_origin()
|
|
4943
5008
|
action = ["sleep", seconds, origin, time_stamp]
|
|
@@ -4995,14 +5060,14 @@ class BaseCase(unittest.TestCase):
|
|
|
4995
5060
|
|
|
4996
5061
|
def activate_cdp_mode(self, url=None, **kwargs):
|
|
4997
5062
|
"""Activate CDP Mode with the URL and kwargs."""
|
|
4998
|
-
if
|
|
5063
|
+
if getattr(self.driver, "_is_using_uc", None):
|
|
4999
5064
|
if self.__is_cdp_swap_needed():
|
|
5000
5065
|
return # CDP Mode is already active
|
|
5001
5066
|
if not self.is_connected():
|
|
5002
5067
|
self.driver.connect()
|
|
5003
5068
|
current_url = self.get_current_url()
|
|
5004
5069
|
if not current_url.startswith(("about", "data", "chrome")):
|
|
5005
|
-
self.
|
|
5070
|
+
self.driver.get("about:blank")
|
|
5006
5071
|
self.driver.uc_open_with_cdp_mode(url, **kwargs)
|
|
5007
5072
|
else:
|
|
5008
5073
|
self.get_new_driver(undetectable=True)
|
|
@@ -5010,11 +5075,17 @@ class BaseCase(unittest.TestCase):
|
|
|
5010
5075
|
self.cdp = self.driver.cdp
|
|
5011
5076
|
if hasattr(self.cdp, "solve_captcha"):
|
|
5012
5077
|
self.solve_captcha = self.cdp.solve_captcha
|
|
5078
|
+
if hasattr(self.cdp, "click_captcha"):
|
|
5079
|
+
self.click_captcha = self.cdp.click_captcha
|
|
5080
|
+
if hasattr(self.cdp, "find_element_by_text"):
|
|
5081
|
+
self.find_element_by_text = self.cdp.find_element_by_text
|
|
5082
|
+
if getattr(self.driver, "_is_using_auth", None):
|
|
5083
|
+
with suppress(Exception):
|
|
5084
|
+
self.cdp.loop.run_until_complete(self.cdp.page.wait(0.25))
|
|
5013
5085
|
self.undetectable = True
|
|
5014
5086
|
|
|
5015
5087
|
def activate_recorder(self):
|
|
5016
|
-
"""Activate Recorder Mode on the
|
|
5017
|
-
For persistent Recorder Mode, use the extension instead."""
|
|
5088
|
+
"""Activate Recorder Mode on the newest tab / window."""
|
|
5018
5089
|
from seleniumbase.js_code.recorder_js import recorder_js
|
|
5019
5090
|
|
|
5020
5091
|
if not self.is_chromium():
|
|
@@ -5027,7 +5098,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5027
5098
|
"The %s Recorder is for Chromium only!\n"
|
|
5028
5099
|
" (Supported browsers: Chrome and Edge)" % sc
|
|
5029
5100
|
)
|
|
5030
|
-
url = self.
|
|
5101
|
+
url = self.get_current_url()
|
|
5031
5102
|
if url.startswith(("data:", "about:", "chrome:", "edge:")):
|
|
5032
5103
|
message = (
|
|
5033
5104
|
"The URL in Recorder-Mode cannot start with: "
|
|
@@ -5035,8 +5106,9 @@ class BaseCase(unittest.TestCase):
|
|
|
5035
5106
|
)
|
|
5036
5107
|
print("\n" + message)
|
|
5037
5108
|
return
|
|
5038
|
-
if self.recorder_ext:
|
|
5109
|
+
if self.recorder_ext and not self.undetectable:
|
|
5039
5110
|
return # The Recorder extension is already active
|
|
5111
|
+
self.switch_to_newest_tab()
|
|
5040
5112
|
with suppress(Exception):
|
|
5041
5113
|
recorder_on = self.get_session_storage_item("recorder_activated")
|
|
5042
5114
|
if not recorder_on == "yes":
|
|
@@ -5659,14 +5731,13 @@ class BaseCase(unittest.TestCase):
|
|
|
5659
5731
|
methodname = self._testMethodName
|
|
5660
5732
|
context_filename = None
|
|
5661
5733
|
if (
|
|
5662
|
-
|
|
5663
|
-
and sb_config.is_context_manager
|
|
5734
|
+
getattr(sb_config, "is_context_manager", None)
|
|
5664
5735
|
and (filename == "base_case.py" or methodname == "runTest")
|
|
5665
5736
|
):
|
|
5666
5737
|
import traceback
|
|
5667
5738
|
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
|
5668
5739
|
test_base = stack_base.split(", in ")[0]
|
|
5669
|
-
if
|
|
5740
|
+
if getattr(self, "cm_filename", None):
|
|
5670
5741
|
filename = self.cm_filename
|
|
5671
5742
|
else:
|
|
5672
5743
|
filename = test_base.split('"')[0]
|
|
@@ -5683,7 +5754,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5683
5754
|
classname = "MyTestClass"
|
|
5684
5755
|
methodname = methodname.replace("[", "__").replace("]", "")
|
|
5685
5756
|
methodname = re.sub(r"[\W]", "_", methodname)
|
|
5686
|
-
if
|
|
5757
|
+
if getattr(self, "is_behave", None):
|
|
5687
5758
|
classname = sb_config.behave_feature.name
|
|
5688
5759
|
classname = classname.replace("/", " ").replace(" & ", " ")
|
|
5689
5760
|
classname = re.sub(r"[^\w" + r"_ " + r"]", "", classname)
|
|
@@ -5751,7 +5822,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5751
5822
|
extra_file_name = "__init__.py"
|
|
5752
5823
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5753
5824
|
if not os.path.exists(extra_file_path):
|
|
5754
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5825
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5755
5826
|
out_file.writelines("\r\n".join(data))
|
|
5756
5827
|
out_file.close()
|
|
5757
5828
|
sys.stdout.write("\nCreated recordings%s__init__.py" % os.sep)
|
|
@@ -5799,7 +5870,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5799
5870
|
extra_file_name = "pytest.ini"
|
|
5800
5871
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5801
5872
|
if not os.path.exists(extra_file_path):
|
|
5802
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5873
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5803
5874
|
out_file.writelines("\r\n".join(data))
|
|
5804
5875
|
out_file.close()
|
|
5805
5876
|
sys.stdout.write("\nCreated recordings%spytest.ini" % os.sep)
|
|
@@ -5820,7 +5891,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5820
5891
|
extra_file_name = "setup.cfg"
|
|
5821
5892
|
extra_file_path = os.path.join(recordings_folder, extra_file_name)
|
|
5822
5893
|
if not os.path.exists(extra_file_path):
|
|
5823
|
-
out_file = open(extra_file_path, "w+", "utf-8")
|
|
5894
|
+
out_file = open(extra_file_path, mode="w+", encoding="utf-8")
|
|
5824
5895
|
out_file.writelines("\r\n".join(data))
|
|
5825
5896
|
out_file.close()
|
|
5826
5897
|
sys.stdout.write("\nCreated recordings%ssetup.cfg" % os.sep)
|
|
@@ -5831,14 +5902,14 @@ class BaseCase(unittest.TestCase):
|
|
|
5831
5902
|
test_id = sb_config._test_id
|
|
5832
5903
|
file_name = test_id.split("::")[0].split("/")[-1].split("\\")[-1]
|
|
5833
5904
|
file_name = file_name.split(".py")[0] + "_rec.py"
|
|
5834
|
-
if
|
|
5905
|
+
if getattr(self, "is_behave", None):
|
|
5835
5906
|
file_name = sb_config.behave_scenario.filename.replace(".", "_")
|
|
5836
5907
|
file_name = file_name.split("/")[-1].split("\\")[-1] + "_rec.py"
|
|
5837
5908
|
file_name = file_name
|
|
5838
5909
|
elif context_filename:
|
|
5839
5910
|
file_name = context_filename
|
|
5840
5911
|
file_path = os.path.join(recordings_folder, file_name)
|
|
5841
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
5912
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5842
5913
|
out_file.writelines("\r\n".join(data))
|
|
5843
5914
|
out_file.close()
|
|
5844
5915
|
rec_message = ">>> RECORDING SAVED as: "
|
|
@@ -5850,7 +5921,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5850
5921
|
if terminal_size > 30 and star_len > terminal_size:
|
|
5851
5922
|
star_len = terminal_size
|
|
5852
5923
|
spc = "\n\n"
|
|
5853
|
-
if
|
|
5924
|
+
if getattr(self, "rec_print", None):
|
|
5854
5925
|
spc = ""
|
|
5855
5926
|
sys.stdout.write("\nCreated recordings%s%s" % (os.sep, file_name))
|
|
5856
5927
|
print()
|
|
@@ -5871,7 +5942,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5871
5942
|
rec_message = rec_message.replace(">>>", c2 + ">>>" + cr)
|
|
5872
5943
|
print("%s%s%s%s%s\n%s" % (spc, rec_message, c1, file_path, cr, stars))
|
|
5873
5944
|
|
|
5874
|
-
if
|
|
5945
|
+
if getattr(self, "rec_behave", None):
|
|
5875
5946
|
# Also generate necessary behave-gherkin files.
|
|
5876
5947
|
self.__process_recorded_behave_actions(srt_actions, colorama)
|
|
5877
5948
|
|
|
@@ -5882,7 +5953,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5882
5953
|
filename = self.__get_filename()
|
|
5883
5954
|
feature_class = None
|
|
5884
5955
|
scenario_test = None
|
|
5885
|
-
if
|
|
5956
|
+
if getattr(self, "is_behave", None):
|
|
5886
5957
|
feature_class = sb_config.behave_feature.name
|
|
5887
5958
|
scenario_test = sb_config.behave_scenario.name
|
|
5888
5959
|
else:
|
|
@@ -5936,11 +6007,11 @@ class BaseCase(unittest.TestCase):
|
|
|
5936
6007
|
os.makedirs(steps_folder)
|
|
5937
6008
|
|
|
5938
6009
|
file_name = filename.split(".")[0]
|
|
5939
|
-
if
|
|
6010
|
+
if getattr(self, "is_behave", None):
|
|
5940
6011
|
file_name = sb_config.behave_scenario.filename.replace(".", "_")
|
|
5941
6012
|
file_name = file_name.split("/")[-1].split("\\")[-1] + "_rec.feature"
|
|
5942
6013
|
file_path = os.path.join(features_folder, file_name)
|
|
5943
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6014
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5944
6015
|
out_file.writelines("\r\n".join(data))
|
|
5945
6016
|
out_file.close()
|
|
5946
6017
|
|
|
@@ -5953,7 +6024,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5953
6024
|
if terminal_size > 30 and star_len > terminal_size:
|
|
5954
6025
|
star_len = terminal_size
|
|
5955
6026
|
spc = "\n"
|
|
5956
|
-
if
|
|
6027
|
+
if getattr(self, "rec_print", None):
|
|
5957
6028
|
spc = ""
|
|
5958
6029
|
print()
|
|
5959
6030
|
if " " not in file_path:
|
|
@@ -5978,7 +6049,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5978
6049
|
file_name = "__init__.py"
|
|
5979
6050
|
file_path = os.path.join(features_folder, file_name)
|
|
5980
6051
|
if not os.path.exists(file_path):
|
|
5981
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6052
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5982
6053
|
out_file.writelines("\r\n".join(data))
|
|
5983
6054
|
out_file.close()
|
|
5984
6055
|
print("Created recordings/features/__init__.py")
|
|
@@ -5991,7 +6062,7 @@ class BaseCase(unittest.TestCase):
|
|
|
5991
6062
|
file_name = "behave.ini"
|
|
5992
6063
|
file_path = os.path.join(features_folder, file_name)
|
|
5993
6064
|
if not os.path.exists(file_path):
|
|
5994
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6065
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
5995
6066
|
out_file.writelines("\r\n".join(data))
|
|
5996
6067
|
out_file.close()
|
|
5997
6068
|
print("Created recordings/features/behave.ini")
|
|
@@ -6030,7 +6101,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6030
6101
|
file_name = "environment.py"
|
|
6031
6102
|
file_path = os.path.join(features_folder, file_name)
|
|
6032
6103
|
if not os.path.exists(file_path):
|
|
6033
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6104
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6034
6105
|
out_file.writelines("\r\n".join(data))
|
|
6035
6106
|
out_file.close()
|
|
6036
6107
|
print("Created recordings/features/environment.py")
|
|
@@ -6040,7 +6111,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6040
6111
|
file_name = "__init__.py"
|
|
6041
6112
|
file_path = os.path.join(steps_folder, file_name)
|
|
6042
6113
|
if not os.path.exists(file_path):
|
|
6043
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6114
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6044
6115
|
out_file.writelines("\r\n".join(data))
|
|
6045
6116
|
out_file.close()
|
|
6046
6117
|
print("Created recordings/features/steps/__init__.py")
|
|
@@ -6051,7 +6122,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6051
6122
|
file_name = "imported.py"
|
|
6052
6123
|
file_path = os.path.join(steps_folder, file_name)
|
|
6053
6124
|
if not os.path.exists(file_path):
|
|
6054
|
-
out_file = open(file_path, "w+", "utf-8")
|
|
6125
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
6055
6126
|
out_file.writelines("\r\n".join(data))
|
|
6056
6127
|
out_file.close()
|
|
6057
6128
|
print("Created recordings/features/steps/imported.py")
|
|
@@ -6278,7 +6349,12 @@ class BaseCase(unittest.TestCase):
|
|
|
6278
6349
|
scroll - the option to scroll to the element first (Default: True)
|
|
6279
6350
|
timeout - the time to wait for the element to appear """
|
|
6280
6351
|
self.__check_scope()
|
|
6281
|
-
if
|
|
6352
|
+
if self.__is_cdp_swap_needed():
|
|
6353
|
+
if page_utils.is_xpath_selector(selector):
|
|
6354
|
+
if "contains(" in selector:
|
|
6355
|
+
self.cdp.highlight(selector)
|
|
6356
|
+
return
|
|
6357
|
+
else:
|
|
6282
6358
|
self._check_browser()
|
|
6283
6359
|
self.__skip_if_esc()
|
|
6284
6360
|
if isinstance(selector, WebElement):
|
|
@@ -6323,6 +6399,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6323
6399
|
By default, "html" will be used as the CSS Selector target.
|
|
6324
6400
|
You can specify how many times in-a-row the action happens."""
|
|
6325
6401
|
self.__check_scope()
|
|
6402
|
+
self._check_browser()
|
|
6326
6403
|
if times < 1:
|
|
6327
6404
|
return
|
|
6328
6405
|
element = self.wait_for_element_present(selector)
|
|
@@ -6345,6 +6422,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6345
6422
|
By default, "html" will be used as the CSS Selector target.
|
|
6346
6423
|
You can specify how many times in-a-row the action happens."""
|
|
6347
6424
|
self.__check_scope()
|
|
6425
|
+
self._check_browser()
|
|
6348
6426
|
if times < 1:
|
|
6349
6427
|
return
|
|
6350
6428
|
element = self.wait_for_element_present(selector)
|
|
@@ -6367,6 +6445,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6367
6445
|
By default, "html" will be used as the CSS Selector target.
|
|
6368
6446
|
You can specify how many times in-a-row the action happens."""
|
|
6369
6447
|
self.__check_scope()
|
|
6448
|
+
self._check_browser()
|
|
6370
6449
|
if times < 1:
|
|
6371
6450
|
return
|
|
6372
6451
|
element = self.wait_for_element_present(selector)
|
|
@@ -6389,6 +6468,7 @@ class BaseCase(unittest.TestCase):
|
|
|
6389
6468
|
By default, "html" will be used as the CSS Selector target.
|
|
6390
6469
|
You can specify how many times in-a-row the action happens."""
|
|
6391
6470
|
self.__check_scope()
|
|
6471
|
+
self._check_browser()
|
|
6392
6472
|
if times < 1:
|
|
6393
6473
|
return
|
|
6394
6474
|
element = self.wait_for_element_present(selector)
|
|
@@ -7297,21 +7377,6 @@ class BaseCase(unittest.TestCase):
|
|
|
7297
7377
|
with pip_find_lock:
|
|
7298
7378
|
with suppress(Exception):
|
|
7299
7379
|
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
|
7300
|
-
if sys.version_info < (3, 9):
|
|
7301
|
-
# Fix bug in newer cryptography for Python 3.7 and 3.8:
|
|
7302
|
-
# "pyo3_runtime.PanicException: Python API call failed"
|
|
7303
|
-
try:
|
|
7304
|
-
import cryptography
|
|
7305
|
-
if cryptography.__version__ != "39.0.2":
|
|
7306
|
-
del cryptography # To get newer ver
|
|
7307
|
-
shared_utils.pip_install(
|
|
7308
|
-
"cryptography", version="39.0.2"
|
|
7309
|
-
)
|
|
7310
|
-
import cryptography
|
|
7311
|
-
except Exception:
|
|
7312
|
-
shared_utils.pip_install(
|
|
7313
|
-
"cryptography", version="39.0.2"
|
|
7314
|
-
)
|
|
7315
7380
|
try:
|
|
7316
7381
|
from pdfminer.high_level import extract_text
|
|
7317
7382
|
except Exception:
|
|
@@ -7603,7 +7668,11 @@ class BaseCase(unittest.TestCase):
|
|
|
7603
7668
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
|
7604
7669
|
if not os.path.exists(destination_folder):
|
|
7605
7670
|
os.makedirs(destination_folder)
|
|
7606
|
-
|
|
7671
|
+
agent = self.get_user_agent()
|
|
7672
|
+
headers = {"user-agent": agent}
|
|
7673
|
+
page_utils._download_file_to(
|
|
7674
|
+
file_url, destination_folder, headers=headers
|
|
7675
|
+
)
|
|
7607
7676
|
if self.recorder_mode and self.__current_url_is_recordable():
|
|
7608
7677
|
if self.get_session_storage_item("pause_recorder") == "no":
|
|
7609
7678
|
time_stamp = self.execute_script("return Date.now();")
|
|
@@ -7627,8 +7696,10 @@ class BaseCase(unittest.TestCase):
|
|
|
7627
7696
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
|
7628
7697
|
if not os.path.exists(destination_folder):
|
|
7629
7698
|
os.makedirs(destination_folder)
|
|
7699
|
+
agent = self.get_user_agent()
|
|
7700
|
+
headers = {"user-agent": agent}
|
|
7630
7701
|
page_utils._download_file_to(
|
|
7631
|
-
file_url, destination_folder, new_file_name
|
|
7702
|
+
file_url, destination_folder, new_file_name, headers=headers
|
|
7632
7703
|
)
|
|
7633
7704
|
|
|
7634
7705
|
def save_data_as(self, data, file_name, destination_folder=None):
|
|
@@ -8740,6 +8811,9 @@ class BaseCase(unittest.TestCase):
|
|
|
8740
8811
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
|
8741
8812
|
timeout = self.__get_new_timeout(timeout)
|
|
8742
8813
|
selector, by = self.__recalculate_selector(selector, by)
|
|
8814
|
+
if self.__is_cdp_swap_needed():
|
|
8815
|
+
self.cdp.set_value(selector, text)
|
|
8816
|
+
return
|
|
8743
8817
|
self.wait_for_ready_state_complete()
|
|
8744
8818
|
element = page_actions.wait_for_element_present(
|
|
8745
8819
|
self.driver, selector, by, timeout
|
|
@@ -8760,10 +8834,14 @@ class BaseCase(unittest.TestCase):
|
|
|
8760
8834
|
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
|
8761
8835
|
timeout = self.__get_new_timeout(timeout)
|
|
8762
8836
|
selector, by = self.__recalculate_selector(selector, by)
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
self.
|
|
8766
|
-
|
|
8837
|
+
element = None
|
|
8838
|
+
if self.__is_cdp_swap_needed():
|
|
8839
|
+
element = self.cdp.select(selector, timeout=timeout)
|
|
8840
|
+
else:
|
|
8841
|
+
self.wait_for_ready_state_complete()
|
|
8842
|
+
element = page_actions.wait_for_element_present(
|
|
8843
|
+
self.driver, selector, by, timeout
|
|
8844
|
+
)
|
|
8767
8845
|
if element.tag_name.lower() in ["input", "textarea"]:
|
|
8768
8846
|
self.js_update_text(selector, text, by=by, timeout=timeout)
|
|
8769
8847
|
return
|
|
@@ -8955,7 +9033,7 @@ class BaseCase(unittest.TestCase):
|
|
|
8955
9033
|
self.__passed_then_skipped = True
|
|
8956
9034
|
self.__will_be_skipped = True
|
|
8957
9035
|
sb_config._results[test_id] = "Skipped"
|
|
8958
|
-
if
|
|
9036
|
+
if getattr(self, "with_db_reporting", None):
|
|
8959
9037
|
if self.is_pytest:
|
|
8960
9038
|
self.__skip_reason = reason
|
|
8961
9039
|
else:
|
|
@@ -9226,9 +9304,9 @@ class BaseCase(unittest.TestCase):
|
|
|
9226
9304
|
"""Same as self.refresh_page()"""
|
|
9227
9305
|
self.refresh_page()
|
|
9228
9306
|
|
|
9229
|
-
def open_new_tab(self, switch_to=True):
|
|
9307
|
+
def open_new_tab(self, switch_to=True, **kwargs):
|
|
9230
9308
|
"""Same as self.open_new_window()"""
|
|
9231
|
-
self.open_new_window(switch_to=switch_to)
|
|
9309
|
+
self.open_new_window(switch_to=switch_to, **kwargs)
|
|
9232
9310
|
|
|
9233
9311
|
def switch_to_tab(self, tab, timeout=None):
|
|
9234
9312
|
"""Same as self.switch_to_window()
|
|
@@ -9253,81 +9331,42 @@ class BaseCase(unittest.TestCase):
|
|
|
9253
9331
|
self, selector, text, by="css selector", timeout=None, retry=False
|
|
9254
9332
|
):
|
|
9255
9333
|
"""Same as self.update_text()"""
|
|
9256
|
-
self.__check_scope()
|
|
9257
|
-
if not timeout:
|
|
9258
|
-
timeout = settings.LARGE_TIMEOUT
|
|
9259
|
-
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
|
9260
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9261
|
-
selector, by = self.__recalculate_selector(selector, by)
|
|
9262
9334
|
self.update_text(selector, text, by=by, timeout=timeout, retry=retry)
|
|
9263
9335
|
|
|
9264
9336
|
def fill(
|
|
9265
9337
|
self, selector, text, by="css selector", timeout=None, retry=False
|
|
9266
9338
|
):
|
|
9267
9339
|
"""Same as self.update_text()"""
|
|
9268
|
-
self.__check_scope()
|
|
9269
|
-
if not timeout:
|
|
9270
|
-
timeout = settings.LARGE_TIMEOUT
|
|
9271
|
-
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
|
9272
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9273
|
-
selector, by = self.__recalculate_selector(selector, by)
|
|
9274
9340
|
self.update_text(selector, text, by=by, timeout=timeout, retry=retry)
|
|
9275
9341
|
|
|
9276
9342
|
def write(
|
|
9277
9343
|
self, selector, text, by="css selector", timeout=None, retry=False
|
|
9278
9344
|
):
|
|
9279
9345
|
"""Same as self.update_text()"""
|
|
9280
|
-
self.__check_scope()
|
|
9281
|
-
if not timeout:
|
|
9282
|
-
timeout = settings.LARGE_TIMEOUT
|
|
9283
|
-
if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:
|
|
9284
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9285
|
-
selector, by = self.__recalculate_selector(selector, by)
|
|
9286
9346
|
self.update_text(selector, text, by=by, timeout=timeout, retry=retry)
|
|
9287
9347
|
|
|
9288
9348
|
def click_link(self, link_text, timeout=None):
|
|
9289
9349
|
"""Same as self.click_link_text()"""
|
|
9290
|
-
self.__check_scope()
|
|
9291
|
-
if not timeout:
|
|
9292
|
-
timeout = settings.SMALL_TIMEOUT
|
|
9293
|
-
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
9294
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9295
9350
|
self.click_link_text(link_text, timeout=timeout)
|
|
9296
9351
|
|
|
9297
9352
|
def click_partial_link(self, partial_link_text, timeout=None):
|
|
9298
9353
|
"""Same as self.click_partial_link_text()"""
|
|
9299
|
-
self.__check_scope()
|
|
9300
|
-
if not timeout:
|
|
9301
|
-
timeout = settings.SMALL_TIMEOUT
|
|
9302
|
-
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
9303
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9304
9354
|
self.click_partial_link_text(partial_link_text, timeout=timeout)
|
|
9305
9355
|
|
|
9306
9356
|
def right_click(self, selector, by="css selector", timeout=None):
|
|
9307
9357
|
"""Same as self.context_click()"""
|
|
9308
|
-
self.__check_scope()
|
|
9309
|
-
if not timeout:
|
|
9310
|
-
timeout = settings.SMALL_TIMEOUT
|
|
9311
|
-
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
9312
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9313
9358
|
self.context_click(selector, by=by, timeout=timeout)
|
|
9314
9359
|
|
|
9360
|
+
def hover_element(self, selector, by="css selector", timeout=None):
|
|
9361
|
+
"""Same as self.hover()"""
|
|
9362
|
+
return self.hover(selector, by=by, timeout=timeout)
|
|
9363
|
+
|
|
9315
9364
|
def hover_on_element(self, selector, by="css selector", timeout=None):
|
|
9316
9365
|
"""Same as self.hover()"""
|
|
9317
|
-
self.__check_scope()
|
|
9318
|
-
if not timeout:
|
|
9319
|
-
timeout = settings.SMALL_TIMEOUT
|
|
9320
|
-
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
9321
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9322
9366
|
return self.hover(selector, by=by, timeout=timeout)
|
|
9323
9367
|
|
|
9324
9368
|
def hover_over_element(self, selector, by="css selector", timeout=None):
|
|
9325
9369
|
"""Same as self.hover()"""
|
|
9326
|
-
self.__check_scope()
|
|
9327
|
-
if not timeout:
|
|
9328
|
-
timeout = settings.SMALL_TIMEOUT
|
|
9329
|
-
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
9330
|
-
timeout = self.__get_new_timeout(timeout)
|
|
9331
9370
|
return self.hover(selector, by=by, timeout=timeout)
|
|
9332
9371
|
|
|
9333
9372
|
def wait_for_element_visible(
|
|
@@ -9652,7 +9691,7 @@ class BaseCase(unittest.TestCase):
|
|
|
9652
9691
|
To force a print during multithreaded tests, use: "sys.stderr.write()".
|
|
9653
9692
|
To print without the new-line character end, use: "sys.stdout.write()".
|
|
9654
9693
|
"""
|
|
9655
|
-
if
|
|
9694
|
+
if getattr(sb_config, "_multithreaded", None):
|
|
9656
9695
|
if not isinstance(msg, str):
|
|
9657
9696
|
with suppress(Exception):
|
|
9658
9697
|
msg = str(msg)
|
|
@@ -10091,6 +10130,21 @@ class BaseCase(unittest.TestCase):
|
|
|
10091
10130
|
if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:
|
|
10092
10131
|
timeout = self.__get_new_timeout(timeout)
|
|
10093
10132
|
if self.__is_cdp_swap_needed():
|
|
10133
|
+
if self.demo_mode:
|
|
10134
|
+
selector, by = self.__recalculate_selector(
|
|
10135
|
+
selector, by, xp_ok=False
|
|
10136
|
+
)
|
|
10137
|
+
a_t = "ASSERT"
|
|
10138
|
+
if self._language != "English":
|
|
10139
|
+
from seleniumbase.fixtures.words import SD
|
|
10140
|
+
|
|
10141
|
+
a_t = SD.translate_assert(self._language)
|
|
10142
|
+
messenger_post = "<b>%s %s</b>: %s" % (
|
|
10143
|
+
a_t, by.upper(), selector
|
|
10144
|
+
)
|
|
10145
|
+
self.__highlight_with_assert_success(
|
|
10146
|
+
messenger_post, selector, by
|
|
10147
|
+
)
|
|
10094
10148
|
self.cdp.assert_element(selector, timeout=timeout)
|
|
10095
10149
|
return True
|
|
10096
10150
|
if isinstance(selector, list):
|
|
@@ -10385,6 +10439,20 @@ class BaseCase(unittest.TestCase):
|
|
|
10385
10439
|
messenger_post, selector, by
|
|
10386
10440
|
)
|
|
10387
10441
|
elif self.__is_cdp_swap_needed():
|
|
10442
|
+
if self.demo_mode:
|
|
10443
|
+
a_t = "ASSERT TEXT"
|
|
10444
|
+
i_n = "in"
|
|
10445
|
+
if self._language != "English":
|
|
10446
|
+
from seleniumbase.fixtures.words import SD
|
|
10447
|
+
|
|
10448
|
+
a_t = SD.translate_assert_text(self._language)
|
|
10449
|
+
i_n = SD.translate_in(self._language)
|
|
10450
|
+
messenger_post = "<b>%s</b>: {%s} %s %s: %s" % (
|
|
10451
|
+
a_t, text, i_n, by.upper(), selector
|
|
10452
|
+
)
|
|
10453
|
+
self.__highlight_with_assert_success(
|
|
10454
|
+
messenger_post, selector, by
|
|
10455
|
+
)
|
|
10388
10456
|
self.cdp.assert_text(text, selector, timeout=timeout)
|
|
10389
10457
|
return True
|
|
10390
10458
|
elif self.__is_shadow_selector(selector):
|
|
@@ -11120,7 +11188,7 @@ class BaseCase(unittest.TestCase):
|
|
|
11120
11188
|
return # Skip the rest when deferred visual asserts are used
|
|
11121
11189
|
the_html = visual_helper.get_sbs_html()
|
|
11122
11190
|
file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE)
|
|
11123
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
11191
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
11124
11192
|
out_file.writelines(the_html)
|
|
11125
11193
|
out_file.close()
|
|
11126
11194
|
|
|
@@ -11280,16 +11348,16 @@ class BaseCase(unittest.TestCase):
|
|
|
11280
11348
|
self.save_screenshot(
|
|
11281
11349
|
baseline_png, visual_baseline_path, selector="body"
|
|
11282
11350
|
)
|
|
11283
|
-
out_file = open(page_url_file, "w+", encoding="utf-8")
|
|
11351
|
+
out_file = open(page_url_file, mode="w+", encoding="utf-8")
|
|
11284
11352
|
out_file.writelines(page_url)
|
|
11285
11353
|
out_file.close()
|
|
11286
|
-
out_file = open(level_1_file, "w+", encoding="utf-8")
|
|
11354
|
+
out_file = open(level_1_file, mode="w+", encoding="utf-8")
|
|
11287
11355
|
out_file.writelines(json.dumps(level_1))
|
|
11288
11356
|
out_file.close()
|
|
11289
|
-
out_file = open(level_2_file, "w+", encoding="utf-8")
|
|
11357
|
+
out_file = open(level_2_file, mode="w+", encoding="utf-8")
|
|
11290
11358
|
out_file.writelines(json.dumps(level_2))
|
|
11291
11359
|
out_file.close()
|
|
11292
|
-
out_file = open(level_3_file, "w+", encoding="utf-8")
|
|
11360
|
+
out_file = open(level_3_file, mode="w+", encoding="utf-8")
|
|
11293
11361
|
out_file.writelines(json.dumps(level_3))
|
|
11294
11362
|
out_file.close()
|
|
11295
11363
|
|
|
@@ -11428,7 +11496,7 @@ class BaseCase(unittest.TestCase):
|
|
|
11428
11496
|
alpha_n_d_name = "".join([x if x.isalnum() else "_" for x in name])
|
|
11429
11497
|
side_by_side_name = "side_by_side_%s.html" % alpha_n_d_name
|
|
11430
11498
|
file_path = os.path.join(test_logpath, side_by_side_name)
|
|
11431
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
11499
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
11432
11500
|
out_file.writelines(the_html)
|
|
11433
11501
|
out_file.close()
|
|
11434
11502
|
|
|
@@ -12120,7 +12188,7 @@ class BaseCase(unittest.TestCase):
|
|
|
12120
12188
|
with suppress(Exception):
|
|
12121
12189
|
os.makedirs(saved_presentations_folder)
|
|
12122
12190
|
file_path = os.path.join(saved_presentations_folder, filename)
|
|
12123
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
12191
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
12124
12192
|
out_file.writelines(the_html)
|
|
12125
12193
|
out_file.close()
|
|
12126
12194
|
if self._output_file_saves:
|
|
@@ -12815,7 +12883,7 @@ class BaseCase(unittest.TestCase):
|
|
|
12815
12883
|
with suppress(Exception):
|
|
12816
12884
|
os.makedirs(saved_charts_folder)
|
|
12817
12885
|
file_path = os.path.join(saved_charts_folder, filename)
|
|
12818
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
12886
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
12819
12887
|
out_file.writelines(the_html)
|
|
12820
12888
|
out_file.close()
|
|
12821
12889
|
if self._output_file_saves:
|
|
@@ -13874,7 +13942,7 @@ class BaseCase(unittest.TestCase):
|
|
|
13874
13942
|
simulateClick(someLink);"""
|
|
13875
13943
|
% css_selector
|
|
13876
13944
|
)
|
|
13877
|
-
if
|
|
13945
|
+
if getattr(self, "recorder_mode", None):
|
|
13878
13946
|
self.save_recorded_actions()
|
|
13879
13947
|
try:
|
|
13880
13948
|
self.execute_script(script)
|
|
@@ -13922,7 +13990,7 @@ class BaseCase(unittest.TestCase):
|
|
|
13922
13990
|
var someLink = arguments[0];
|
|
13923
13991
|
simulateClick(someLink);"""
|
|
13924
13992
|
)
|
|
13925
|
-
if
|
|
13993
|
+
if getattr(self, "recorder_mode", None):
|
|
13926
13994
|
self.save_recorded_actions()
|
|
13927
13995
|
try:
|
|
13928
13996
|
self.execute_script(script, element)
|
|
@@ -14129,7 +14197,7 @@ class BaseCase(unittest.TestCase):
|
|
|
14129
14197
|
selector = self.convert_to_css_selector(selector, by=by)
|
|
14130
14198
|
selector = self.__make_css_match_first_element_only(selector)
|
|
14131
14199
|
click_script = """jQuery('%s')[0].click();""" % selector
|
|
14132
|
-
if
|
|
14200
|
+
if getattr(self, "recorder_mode", None):
|
|
14133
14201
|
self.save_recorded_actions()
|
|
14134
14202
|
self.safe_execute_script(click_script)
|
|
14135
14203
|
|
|
@@ -14285,8 +14353,7 @@ class BaseCase(unittest.TestCase):
|
|
|
14285
14353
|
def __needs_minimum_wait(self):
|
|
14286
14354
|
if (
|
|
14287
14355
|
self.page_load_strategy == "none"
|
|
14288
|
-
and
|
|
14289
|
-
and settings.SKIP_JS_WAITS
|
|
14356
|
+
and getattr(settings, "SKIP_JS_WAITS", None)
|
|
14290
14357
|
):
|
|
14291
14358
|
return True
|
|
14292
14359
|
else:
|
|
@@ -14522,7 +14589,8 @@ class BaseCase(unittest.TestCase):
|
|
|
14522
14589
|
sb_config._virtual_display = self._xvfb_display
|
|
14523
14590
|
if "DISPLAY" not in os.environ.keys():
|
|
14524
14591
|
print(
|
|
14525
|
-
"\
|
|
14592
|
+
"\n X11 display failed! Is Xvfb installed? "
|
|
14593
|
+
"\n Try this: `sudo apt install -y xvfb`"
|
|
14526
14594
|
)
|
|
14527
14595
|
self.__activate_standard_virtual_display()
|
|
14528
14596
|
else:
|
|
@@ -14535,7 +14603,10 @@ class BaseCase(unittest.TestCase):
|
|
|
14535
14603
|
print("\n" + str(e.msg))
|
|
14536
14604
|
else:
|
|
14537
14605
|
print(e)
|
|
14538
|
-
print(
|
|
14606
|
+
print(
|
|
14607
|
+
"\n X11 display failed! Is Xvfb installed? "
|
|
14608
|
+
"\n Try this: `sudo apt install -y xvfb`"
|
|
14609
|
+
)
|
|
14539
14610
|
self.__activate_standard_virtual_display()
|
|
14540
14611
|
return
|
|
14541
14612
|
pyautogui_is_installed = False
|
|
@@ -14614,10 +14685,7 @@ class BaseCase(unittest.TestCase):
|
|
|
14614
14685
|
|
|
14615
14686
|
def __disable_beforeunload_as_needed(self):
|
|
14616
14687
|
"""Disables beforeunload as needed. Also resets frame_switch state."""
|
|
14617
|
-
if (
|
|
14618
|
-
hasattr(self, "_disable_beforeunload")
|
|
14619
|
-
and self._disable_beforeunload
|
|
14620
|
-
):
|
|
14688
|
+
if getattr(self, "_disable_beforeunload", None):
|
|
14621
14689
|
self.disable_beforeunload()
|
|
14622
14690
|
if self.recorder_mode:
|
|
14623
14691
|
try:
|
|
@@ -15418,9 +15486,9 @@ class BaseCase(unittest.TestCase):
|
|
|
15418
15486
|
self.__skip_reason = None
|
|
15419
15487
|
self.testcase_manager.insert_testcase_data(data_payload)
|
|
15420
15488
|
self.case_start_time = int(time.time() * 1000.0)
|
|
15421
|
-
elif
|
|
15489
|
+
elif getattr(self, "is_behave", None):
|
|
15422
15490
|
self.__initialize_variables()
|
|
15423
|
-
elif
|
|
15491
|
+
elif getattr(self, "is_nosetest", None):
|
|
15424
15492
|
pass # Setup performed in plugins for pynose
|
|
15425
15493
|
else:
|
|
15426
15494
|
# Pure Python run. (Eg. SB() and Driver() Managers)
|
|
@@ -15511,7 +15579,7 @@ class BaseCase(unittest.TestCase):
|
|
|
15511
15579
|
"Invalid input for Mobile Emulator device metrics!\n"
|
|
15512
15580
|
"Expecting a comma-separated string with integer values\n"
|
|
15513
15581
|
"for Width/Height, and an int or float for Pixel-Ratio.\n"
|
|
15514
|
-
'Example: --metrics="
|
|
15582
|
+
'Example: --metrics="412,732,3" '
|
|
15515
15583
|
)
|
|
15516
15584
|
if len(metrics_list) != 3:
|
|
15517
15585
|
raise Exception(exception_string)
|
|
@@ -15612,7 +15680,7 @@ class BaseCase(unittest.TestCase):
|
|
|
15612
15680
|
)
|
|
15613
15681
|
raise Exception(message)
|
|
15614
15682
|
|
|
15615
|
-
if not
|
|
15683
|
+
if not getattr(self, "is_nosetest", None):
|
|
15616
15684
|
# Xvfb Virtual Display activation for Linux
|
|
15617
15685
|
self.__activate_virtual_display_as_needed()
|
|
15618
15686
|
|
|
@@ -15788,10 +15856,7 @@ class BaseCase(unittest.TestCase):
|
|
|
15788
15856
|
self.__last_page_screenshot_png is for all screenshot log files."""
|
|
15789
15857
|
SCREENSHOT_SKIPPED = constants.Warnings.SCREENSHOT_SKIPPED
|
|
15790
15858
|
SCREENSHOT_UNDEFINED = constants.Warnings.SCREENSHOT_UNDEFINED
|
|
15791
|
-
if (
|
|
15792
|
-
hasattr(self, "no_screenshot_after_test")
|
|
15793
|
-
and self.no_screenshot_after_test
|
|
15794
|
-
):
|
|
15859
|
+
if getattr(self, "no_screenshot_after_test", None):
|
|
15795
15860
|
from seleniumbase.core import encoded_images
|
|
15796
15861
|
|
|
15797
15862
|
NO_SCREENSHOT = encoded_images.get_no_screenshot_png()
|
|
@@ -15822,10 +15887,7 @@ class BaseCase(unittest.TestCase):
|
|
|
15822
15887
|
ignore_test_time_limit=True,
|
|
15823
15888
|
)
|
|
15824
15889
|
try:
|
|
15825
|
-
if (
|
|
15826
|
-
hasattr(settings, "SCREENSHOT_WITH_BACKGROUND")
|
|
15827
|
-
and settings.SCREENSHOT_WITH_BACKGROUND
|
|
15828
|
-
):
|
|
15890
|
+
if getattr(settings, "SCREENSHOT_WITH_BACKGROUND", None):
|
|
15829
15891
|
self.__last_page_screenshot = (
|
|
15830
15892
|
self.driver.get_screenshot_as_base64()
|
|
15831
15893
|
)
|
|
@@ -15896,11 +15958,10 @@ class BaseCase(unittest.TestCase):
|
|
|
15896
15958
|
exc_message = None
|
|
15897
15959
|
if (
|
|
15898
15960
|
hasattr(self, "_outcome")
|
|
15899
|
-
and
|
|
15900
|
-
and self._outcome.errors
|
|
15961
|
+
and getattr(self._outcome, "errors", None)
|
|
15901
15962
|
):
|
|
15902
15963
|
try:
|
|
15903
|
-
exc_message = self._outcome.errors[
|
|
15964
|
+
exc_message = self._outcome.errors[-1][1][1]
|
|
15904
15965
|
except Exception:
|
|
15905
15966
|
exc_message = "(Unknown Exception)"
|
|
15906
15967
|
else:
|
|
@@ -15985,8 +16046,7 @@ class BaseCase(unittest.TestCase):
|
|
|
15985
16046
|
def __delay_driver_quit(self):
|
|
15986
16047
|
delay_driver_quit = False
|
|
15987
16048
|
if (
|
|
15988
|
-
|
|
15989
|
-
and self._using_sb_fixture
|
|
16049
|
+
getattr(self, "_using_sb_fixture", None)
|
|
15990
16050
|
and "--pdb" in sys.argv
|
|
15991
16051
|
and self.__has_exception()
|
|
15992
16052
|
and len(self._drivers_list) == 1
|
|
@@ -16042,14 +16102,22 @@ class BaseCase(unittest.TestCase):
|
|
|
16042
16102
|
has_exception = False
|
|
16043
16103
|
if hasattr(sys, "last_traceback") and sys.last_traceback is not None:
|
|
16044
16104
|
has_exception = True
|
|
16045
|
-
elif
|
|
16105
|
+
elif getattr(self, "is_context_manager", None):
|
|
16046
16106
|
if self.with_testing_base and self._has_failure:
|
|
16047
16107
|
return True
|
|
16048
16108
|
else:
|
|
16049
16109
|
return False
|
|
16050
16110
|
elif hasattr(self, "_outcome") and hasattr(self._outcome, "errors"):
|
|
16051
|
-
if
|
|
16052
|
-
|
|
16111
|
+
if python3_11_or_newer:
|
|
16112
|
+
if (
|
|
16113
|
+
self._outcome.errors
|
|
16114
|
+
and self._outcome.errors[-1]
|
|
16115
|
+
and self._outcome.errors[-1][1]
|
|
16116
|
+
):
|
|
16117
|
+
has_exception = True
|
|
16118
|
+
else:
|
|
16119
|
+
if self._outcome.errors:
|
|
16120
|
+
has_exception = True
|
|
16053
16121
|
else:
|
|
16054
16122
|
has_exception = sys.exc_info()[1] is not None
|
|
16055
16123
|
if self.__will_be_skipped and hasattr(self, "_using_sb_fixture"):
|
|
@@ -16058,7 +16126,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16058
16126
|
|
|
16059
16127
|
def __get_test_id(self):
|
|
16060
16128
|
"""The id used in various places such as the test log path."""
|
|
16061
|
-
if
|
|
16129
|
+
if getattr(self, "is_behave", None):
|
|
16062
16130
|
file_name = sb_config.behave_scenario.filename
|
|
16063
16131
|
file_name = file_name.replace("/", ".").replace("\\", ".")
|
|
16064
16132
|
scenario_name = sb_config.behave_scenario.name
|
|
@@ -16068,7 +16136,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16068
16136
|
scenario_name = scenario_name.replace(" ", "_")
|
|
16069
16137
|
test_id = "%s.%s" % (file_name, scenario_name)
|
|
16070
16138
|
return test_id
|
|
16071
|
-
elif
|
|
16139
|
+
elif getattr(self, "is_context_manager", None):
|
|
16072
16140
|
if hasattr(self, "_manager_saved_id"):
|
|
16073
16141
|
self.__saved_id = self._manager_saved_id
|
|
16074
16142
|
if self.__saved_id:
|
|
@@ -16080,7 +16148,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16080
16148
|
import traceback
|
|
16081
16149
|
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
|
|
16082
16150
|
test_base = stack_base.split(", in ")[0]
|
|
16083
|
-
if
|
|
16151
|
+
if getattr(self, "cm_filename", None):
|
|
16084
16152
|
filename = self.cm_filename
|
|
16085
16153
|
else:
|
|
16086
16154
|
filename = test_base.split('"')[0]
|
|
@@ -16095,7 +16163,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16095
16163
|
)
|
|
16096
16164
|
if self._sb_test_identifier and len(str(self._sb_test_identifier)) > 6:
|
|
16097
16165
|
test_id = self._sb_test_identifier
|
|
16098
|
-
elif
|
|
16166
|
+
elif getattr(self, "_using_sb_fixture", None):
|
|
16099
16167
|
test_id = sb_config._latest_display_id
|
|
16100
16168
|
test_id = test_id.replace(".py::", ".").replace("::", ".")
|
|
16101
16169
|
test_id = test_id.replace("/", ".").replace("\\", ".")
|
|
@@ -16117,7 +16185,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16117
16185
|
return full_name.split("] ")[0] + "]"
|
|
16118
16186
|
else:
|
|
16119
16187
|
return full_name.split(" ")[0]
|
|
16120
|
-
if
|
|
16188
|
+
if getattr(self, "is_behave", None):
|
|
16121
16189
|
return self.__get_test_id()
|
|
16122
16190
|
test_id = "%s.%s.%s" % (
|
|
16123
16191
|
self.__class__.__module__.split(".")[-1],
|
|
@@ -16138,7 +16206,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16138
16206
|
return full_name.split("] ")[0] + "]"
|
|
16139
16207
|
else:
|
|
16140
16208
|
return full_name.split(" ")[0]
|
|
16141
|
-
if
|
|
16209
|
+
if getattr(self, "is_behave", None):
|
|
16142
16210
|
file_name = sb_config.behave_scenario.filename
|
|
16143
16211
|
line_num = sb_config.behave_line_num
|
|
16144
16212
|
scenario_name = sb_config.behave_scenario.name
|
|
@@ -16171,7 +16239,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16171
16239
|
if "PYTEST_CURRENT_TEST" in os.environ:
|
|
16172
16240
|
test_id = os.environ["PYTEST_CURRENT_TEST"].split(" ")[0]
|
|
16173
16241
|
filename = test_id.split("::")[0].split("/")[-1]
|
|
16174
|
-
elif
|
|
16242
|
+
elif getattr(self, "is_behave", None):
|
|
16175
16243
|
filename = sb_config.behave_scenario.filename
|
|
16176
16244
|
filename = filename.split("/")[-1].split("\\")[-1]
|
|
16177
16245
|
else:
|
|
@@ -16207,8 +16275,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16207
16275
|
sb_config._pdb_failure = True
|
|
16208
16276
|
elif (
|
|
16209
16277
|
self.is_pytest
|
|
16210
|
-
and
|
|
16211
|
-
and sb_config._pdb_failure
|
|
16278
|
+
and getattr(sb_config, "_pdb_failure", None)
|
|
16212
16279
|
and not has_exception
|
|
16213
16280
|
):
|
|
16214
16281
|
return # Handle case where "pytest --pdb" marks failures as Passed
|
|
@@ -16378,7 +16445,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16378
16445
|
dash_pie = json.dumps(sb_config._saved_dashboard_pie)
|
|
16379
16446
|
dash_pie_loc = constants.Dashboard.DASH_PIE
|
|
16380
16447
|
pie_path = os.path.join(abs_path, dash_pie_loc)
|
|
16381
|
-
pie_file = open(pie_path, "w+", encoding="utf-8")
|
|
16448
|
+
pie_file = open(pie_path, mode="w+", encoding="utf-8")
|
|
16382
16449
|
pie_file.writelines(dash_pie)
|
|
16383
16450
|
pie_file.close()
|
|
16384
16451
|
DASH_PIE_PNG_1 = constants.Dashboard.get_dash_pie_1()
|
|
@@ -16538,7 +16605,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16538
16605
|
)
|
|
16539
16606
|
abs_path = os.path.abspath(".")
|
|
16540
16607
|
file_path = os.path.join(abs_path, "dashboard.html")
|
|
16541
|
-
out_file = open(file_path, "w+", encoding="utf-8")
|
|
16608
|
+
out_file = open(file_path, mode="w+", encoding="utf-8")
|
|
16542
16609
|
out_file.writelines(the_html)
|
|
16543
16610
|
out_file.close()
|
|
16544
16611
|
sb_config._dash_html = the_html
|
|
@@ -16551,7 +16618,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16551
16618
|
dash_json = json.dumps((_results, _display_id, _rt, _tlp, d_stats))
|
|
16552
16619
|
dash_json_loc = constants.Dashboard.DASH_JSON
|
|
16553
16620
|
dash_jsonpath = os.path.join(abs_path, dash_json_loc)
|
|
16554
|
-
dash_json_file = open(dash_jsonpath, "w+", encoding="utf-8")
|
|
16621
|
+
dash_json_file = open(dash_jsonpath, mode="w+", encoding="utf-8")
|
|
16555
16622
|
dash_json_file.writelines(dash_json)
|
|
16556
16623
|
dash_json_file.close()
|
|
16557
16624
|
|
|
@@ -16602,7 +16669,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16602
16669
|
self.__check_scope()
|
|
16603
16670
|
except Exception:
|
|
16604
16671
|
return
|
|
16605
|
-
if
|
|
16672
|
+
if getattr(self, "recorder_mode", None):
|
|
16606
16673
|
# In case tearDown() leaves the origin, save actions first.
|
|
16607
16674
|
self.save_recorded_actions()
|
|
16608
16675
|
if (
|
|
@@ -16797,7 +16864,7 @@ class BaseCase(unittest.TestCase):
|
|
|
16797
16864
|
if not hasattr(self, "_using_sb_fixture") and self.__called_teardown:
|
|
16798
16865
|
# This test already called tearDown()
|
|
16799
16866
|
return
|
|
16800
|
-
if
|
|
16867
|
+
if getattr(self, "recorder_mode", None):
|
|
16801
16868
|
page_actions._reconnect_if_disconnected(self.driver)
|
|
16802
16869
|
try:
|
|
16803
16870
|
self.__process_recorded_actions()
|
|
@@ -17032,7 +17099,7 @@ class BaseCase(unittest.TestCase):
|
|
|
17032
17099
|
self.testcase_manager.update_testcase_log_url(data_payload)
|
|
17033
17100
|
else:
|
|
17034
17101
|
# (Pynose / Behave / Pure Python)
|
|
17035
|
-
if
|
|
17102
|
+
if getattr(self, "is_behave", None):
|
|
17036
17103
|
if sb_config.behave_scenario.status.name == "failed":
|
|
17037
17104
|
has_exception = True
|
|
17038
17105
|
sb_config._has_exception = True
|
|
@@ -17092,8 +17159,8 @@ class BaseCase(unittest.TestCase):
|
|
|
17092
17159
|
self._last_page_url = self.get_current_url()
|
|
17093
17160
|
except Exception:
|
|
17094
17161
|
self._last_page_url = "(Error: Unknown URL)"
|
|
17095
|
-
if
|
|
17096
|
-
if
|
|
17162
|
+
if getattr(self, "is_behave", None) and has_exception:
|
|
17163
|
+
if getattr(sb_config, "pdb_option", None):
|
|
17097
17164
|
if (
|
|
17098
17165
|
hasattr(sb_config, "behave_step")
|
|
17099
17166
|
and hasattr(sb_config.behave_step, "exc_traceback")
|
|
@@ -17101,24 +17168,14 @@ class BaseCase(unittest.TestCase):
|
|
|
17101
17168
|
self.__activate_behave_post_mortem_debug_mode()
|
|
17102
17169
|
if self._final_debug:
|
|
17103
17170
|
self.__activate_debug_mode_in_teardown()
|
|
17104
|
-
elif (
|
|
17105
|
-
hasattr(sb_config, "_do_sb_post_mortem")
|
|
17106
|
-
and sb_config._do_sb_post_mortem
|
|
17107
|
-
):
|
|
17171
|
+
elif getattr(sb_config, "_do_sb_post_mortem", None):
|
|
17108
17172
|
self.__activate_sb_mgr_post_mortem_debug_mode()
|
|
17109
|
-
elif (
|
|
17110
|
-
hasattr(sb_config, "_do_sb_final_trace")
|
|
17111
|
-
and sb_config._do_sb_final_trace
|
|
17112
|
-
):
|
|
17173
|
+
elif getattr(sb_config, "_do_sb_final_trace", None):
|
|
17113
17174
|
self.__activate_debug_mode_in_teardown()
|
|
17114
17175
|
# (Pynose / Behave / Pure Python) Close all open browser windows
|
|
17115
17176
|
self.__quit_all_drivers()
|
|
17116
17177
|
# Resume tearDown() for all test runners, (Pytest / Pynose / Behave)
|
|
17117
|
-
if (
|
|
17118
|
-
hasattr(self, "_xvfb_display")
|
|
17119
|
-
and self._xvfb_display
|
|
17120
|
-
and not self._reuse_session
|
|
17121
|
-
):
|
|
17178
|
+
if getattr(self, "_xvfb_display", None) and not self._reuse_session:
|
|
17122
17179
|
# Stop the Xvfb virtual display launched from BaseCase
|
|
17123
17180
|
try:
|
|
17124
17181
|
if hasattr(self._xvfb_display, "stop"):
|
|
@@ -17130,16 +17187,9 @@ class BaseCase(unittest.TestCase):
|
|
|
17130
17187
|
except Exception:
|
|
17131
17188
|
pass
|
|
17132
17189
|
if (
|
|
17133
|
-
|
|
17134
|
-
and sb_config._virtual_display
|
|
17190
|
+
getattr(sb_config, "_virtual_display", None)
|
|
17135
17191
|
and hasattr(sb_config._virtual_display, "stop")
|
|
17136
|
-
and (
|
|
17137
|
-
not hasattr(sb_config, "reuse_session")
|
|
17138
|
-
or (
|
|
17139
|
-
hasattr(sb_config, "reuse_session")
|
|
17140
|
-
and not sb_config.reuse_session
|
|
17141
|
-
)
|
|
17142
|
-
)
|
|
17192
|
+
and not getattr(sb_config, "reuse_session", None)
|
|
17143
17193
|
):
|
|
17144
17194
|
# CDP Mode may launch a 2nd Xvfb virtual display
|
|
17145
17195
|
try:
|