Skip to content

Commit 355fad6

Browse files
authored
Merge pull request #588 from seleniumbase/improved-exception-handling
Improve exception-handling, and more
2 parents 46ac868 + e919d64 commit 355fad6

File tree

11 files changed

+139
-31
lines changed

11 files changed

+139
-31
lines changed

examples/timeout_test.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
""" This test fails on purpose to demonstrate the time-limit feature
2-
for tests that run longer than the time limit specified in seconds.
3-
Usage: (inside tests) -> self.set_time_limit(SECONDS) """
2+
for tests that run longer than the time limit specified (seconds).
3+
The time-limit clock starts after the browser has fully launched,
4+
which is after pytest starts it's own internal clock for tests.
5+
Usage: (inside tests) => self.set_time_limit(SECONDS)
6+
Usage: (command-line) => --time-limit=SECONDS """
47

58
import pytest
69
from seleniumbase import BaseCase
@@ -10,6 +13,6 @@ class MyTestClass(BaseCase):
1013

1114
@pytest.mark.expected_failure
1215
def test_time_limit_feature(self):
13-
self.set_time_limit(6) # Test fails if run-time exceeds limit
16+
self.set_time_limit(5) # Fail test if time exceeds 5 seconds
1417
self.open("https://xkcd.com/1658/")
1518
self.sleep(7)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from seleniumbase import BaseCase
2+
3+
4+
class MyTestClass(BaseCase):
5+
6+
def test_example_1(self):
7+
url = "https://store.xkcd.com/collections/everything"
8+
self.open(url)
9+
self.update_text("input.search-input", "xkcd book\n")
10+
self.assert_exact_text("xkcd: volume 0", "h3")
11+
self.click("li.checkout-link")
12+
self.assert_text("Shopping Cart", "#page-title")
13+
self.assert_element("div#umbrella")
14+
self.open("https://xkcd.com/353/")
15+
self.assert_title("xkcd: Python")
16+
self.assert_element('img[alt="Python"]')
17+
self.click('a[rel="license"]')
18+
self.assert_text("back to this page")
19+
self.go_back()
20+
self.click("link=About")
21+
self.assert_text("xkcd.com", "h2")

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pip>=20.1.1
22
packaging>=20.4
33
setuptools>=44.1.0;python_version<"3.5"
4-
setuptools>=46.4.0;python_version>="3.5"
4+
setuptools>=47.1.1;python_version>="3.5"
55
setuptools-scm>=4.1.1
66
wheel>=0.34.2
77
six==1.15.0

seleniumbase/common/exceptions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
""" SeleniumBase Exceptions
2+
NoSuchFileException => Used by self.assert_downloaded_file(...)
3+
TimeLimitExceededException => Used by "--time-limit=SECONDS"
4+
"""
5+
6+
7+
class NoSuchFileException(Exception):
8+
pass
9+
10+
11+
class TimeLimitExceededException(Exception):
12+
pass

seleniumbase/fixtures/base_case.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4955,12 +4955,6 @@ def setUp(self, masterqa_mode=False):
49554955
""" >>> "pip install -r requirements.txt"\n"""
49564956
""" >>> "python setup.py install" """)
49574957

4958-
# Configure the test time limit (if used)
4959-
self.set_time_limit(self.time_limit)
4960-
4961-
# Set the start time for the test (in ms)
4962-
sb_config.start_time_ms = int(time.time() * 1000.0)
4963-
49644958
# Parse the settings file
49654959
if self.settings_file:
49664960
settings_parser.set_settings(self.settings_file)
@@ -5049,6 +5043,14 @@ def setUp(self, masterqa_mode=False):
50495043
if self._reuse_session:
50505044
sb_config.shared_driver = self.driver
50515045

5046+
# Configure the test time limit (if used).
5047+
self.set_time_limit(self.time_limit)
5048+
5049+
# Set the start time for the test (in ms).
5050+
# Although the pytest clock starts before setUp() begins,
5051+
# the time-limit clock starts at the end of the setUp() method.
5052+
sb_config.start_time_ms = int(time.time() * 1000.0)
5053+
50525054
def __set_last_page_screenshot(self):
50535055
""" self.__last_page_screenshot is only for pytest html report logs
50545056
self.__last_page_screenshot_png is for all screenshot log files """

seleniumbase/fixtures/errors.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
"""
2-
This module contains test-state related exceptions.
2+
SeleniumBase MySQL plugin-related exceptions.
33
Raising one of these in a test will cause the
4-
test-state to be logged appropriately in the database
4+
test-state to be logged appropriately in the DB
55
for tests that use the SeleniumBase MySQL plugin.
66
"""
77

88

99
class BlockedTest(Exception):
10-
"""Raise this to mark a test as Blocked"""
10+
""" Raise this to mark a test as Blocked in the DB. """
1111
pass
1212

1313

1414
class SkipTest(Exception):
15-
"""Raise this to mark a test as Skipped."""
15+
""" Raise this to mark a test as Skipped in the DB. """
1616
pass
1717

1818

1919
class DeprecatedTest(Exception):
20-
"""Raise this to mark a test as Deprecated."""
20+
""" Raise this to mark a test as Deprecated in the DB. """
2121
pass

seleniumbase/fixtures/js_utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ def wait_for_ready_state_complete(driver, timeout=settings.EXTREME_TIMEOUT):
2525
stop_ms = start_ms + (timeout * 1000.0)
2626
for x in range(int(timeout * 10)):
2727
shared_utils.check_if_time_limit_exceeded()
28+
try:
29+
# If there's an alert, skip
30+
driver.switch_to.alert
31+
return
32+
except Exception:
33+
# If there's no alert, continue
34+
pass
2835
try:
2936
ready_state = driver.execute_script("return document.readyState")
3037
except WebDriverException:
@@ -49,6 +56,13 @@ def execute_async_script(driver, script, timeout=settings.EXTREME_TIMEOUT):
4956

5057

5158
def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs):
59+
try:
60+
# If there's an alert, skip
61+
driver.switch_to.alert
62+
return
63+
except Exception:
64+
# If there's no alert, continue
65+
pass
5266
if not settings.WAIT_FOR_ANGULARJS:
5367
return
5468

seleniumbase/fixtures/page_actions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ def hover_element(driver, element):
114114

115115

116116
def timeout_exception(exception, message):
117-
message = s_utils.format_exc(exception, message)
118-
raise Exception(message)
117+
exc, message = s_utils.format_exc(exception, message)
118+
raise exc(message)
119119

120120

121121
def hover_and_click(driver, hover_selector, click_selector,

seleniumbase/fixtures/shared_utils.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
from selenium.webdriver.remote.errorhandler import NoAlertPresentException
88
from selenium.webdriver.remote.errorhandler import NoSuchFrameException
99
from selenium.webdriver.remote.errorhandler import NoSuchWindowException
10+
from seleniumbase.common.exceptions import NoSuchFileException
11+
from seleniumbase.common.exceptions import TimeLimitExceededException
1012
from seleniumbase import config as sb_config
1113

1214

@@ -15,27 +17,48 @@ def format_exc(exception, message):
1517
Formats an exception message to make the output cleaner.
1618
"""
1719
if exception == Exception:
18-
pass
20+
exc = Exception
21+
return exc, message
1922
elif exception == ElementNotVisibleException:
20-
message = "ElementNotVisibleException: %s" % message
23+
exc = ElementNotVisibleException
24+
elif exception == "ElementNotVisibleException":
25+
exc = ElementNotVisibleException
2126
elif exception == NoSuchElementException:
22-
message = "NoSuchElementException: %s" % message
27+
exc = NoSuchElementException
28+
elif exception == "NoSuchElementException":
29+
exc = NoSuchElementException
2330
elif exception == NoAlertPresentException:
24-
message = "NoAlertPresentException: %s" % message
31+
exc = NoAlertPresentException
32+
elif exception == "NoAlertPresentException":
33+
exc = NoAlertPresentException
2534
elif exception == NoSuchFrameException:
26-
message = "NoSuchFrameException: %s" % message
35+
exc = NoSuchFrameException
36+
elif exception == "NoSuchFrameException":
37+
exc = NoSuchFrameException
2738
elif exception == NoSuchWindowException:
28-
message = "NoSuchWindowException: %s" % message
39+
exc = NoSuchWindowException
40+
elif exception == "NoSuchWindowException":
41+
exc = NoSuchWindowException
42+
elif exception == "NoSuchFileException":
43+
exc = NoSuchFileException
2944
elif type(exception) is str:
45+
exc = Exception
3046
message = "%s: %s" % (exception, message)
47+
return exc, message
3148
else:
32-
pass
49+
exc = Exception
50+
return exc, message
51+
message = _format_message(message)
52+
return exc, message
53+
54+
55+
def _format_message(message):
56+
message = "\n " + message
3357
return message
3458

3559

3660
def __time_limit_exceeded(message):
37-
raise Exception(
38-
"TimeLimitExceeded: %s" % message)
61+
raise TimeLimitExceededException(message)
3962

4063

4164
def check_if_time_limit_exceeded():
@@ -52,4 +75,5 @@ def check_if_time_limit_exceeded():
5275
message = (
5376
"This test has exceeded the time limit of %s second%s!"
5477
"" % (display_time_limit, plural))
78+
message = _format_message(message)
5579
__time_limit_exceeded(message)

seleniumbase/translate/translator.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -493,14 +493,14 @@ def main():
493493

494494
new_sb_lines = []
495495
for line in seleniumbase_lines:
496-
line_length = len(line)
497-
line_length2 = len(line)
498-
line_length = get_width(line)
496+
line_length2 = len(line) # Normal Python string length used
497+
line_length = get_width(line) # Special characters count 2X
499498
if line_length > code_width:
500499
code_width = line_length
501500

502501
if console_width:
503-
# If line is larger than console_width, try to optimize it
502+
# If line is larger than console_width, try to optimize it.
503+
# Smart Python word wrap to be used with valid indentation.
504504
if line_length + w > console_width: # 5 is line number ws
505505
if line.count(' # ') == 1: # Has comments like this
506506
if get_width(
@@ -582,6 +582,38 @@ def main():
582582
else:
583583
new_sb_lines.append(line)
584584
continue
585+
elif line.count('= "') == 1 and line.count('://') == 1:
586+
whitespace = line_length2 - len(line.lstrip())
587+
new_ws = line[0:whitespace] + " "
588+
line1 = line.split('://')[0] + '://" \\'
589+
line2 = new_ws + '"' + line.split('://')[1]
590+
new_sb_lines.append(line1)
591+
if get_width(line2) + w > console_width:
592+
if line2.count('/') > 0:
593+
slash_one = line2.find('/')
594+
line2a = line2[:slash_one+1] + '" \\'
595+
line2b = new_ws + '"' + line2[slash_one+1:]
596+
new_sb_lines.append(line2a)
597+
new_sb_lines.append(line2b)
598+
continue
599+
new_sb_lines.append(line2)
600+
continue
601+
elif line.count("= '") == 1 and line.count('://') == 1:
602+
whitespace = line_length2 - len(line.lstrip())
603+
new_ws = line[0:whitespace] + " "
604+
line1 = line.split('://')[0] + '://" \\'
605+
line2 = new_ws + "'" + line.split('://')[1]
606+
new_sb_lines.append(line1)
607+
if get_width(line2) + w > console_width:
608+
if line2.count('/') > 0:
609+
slash_one = line2.find('/')
610+
line2a = line2[:slash_one+1] + "' \\"
611+
line2b = new_ws + "'" + line2[slash_one+1:]
612+
new_sb_lines.append(line2a)
613+
new_sb_lines.append(line2b)
614+
continue
615+
new_sb_lines.append(line2)
616+
continue
585617
new_sb_lines.append(line)
586618

587619
if new_sb_lines:

0 commit comments

Comments
 (0)