seleniumbase 4.15.14__py3-none-any.whl → 4.16.0__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.
Files changed (56) hide show
  1. sbase/__init__.py +1 -0
  2. seleniumbase/__init__.py +1 -0
  3. seleniumbase/__version__.py +1 -1
  4. seleniumbase/behave/behave_sb.py +12 -19
  5. seleniumbase/common/exceptions.py +5 -0
  6. seleniumbase/config/settings.py +7 -0
  7. seleniumbase/console_scripts/ReadMe.md +2 -2
  8. seleniumbase/console_scripts/run.py +5 -4
  9. seleniumbase/console_scripts/sb_behave_gui.py +6 -9
  10. seleniumbase/console_scripts/sb_caseplans.py +2 -5
  11. seleniumbase/console_scripts/sb_commander.py +5 -8
  12. seleniumbase/console_scripts/sb_install.py +43 -54
  13. seleniumbase/console_scripts/sb_mkchart.py +12 -7
  14. seleniumbase/console_scripts/sb_mkfile.py +1 -2
  15. seleniumbase/console_scripts/sb_mkpres.py +6 -1
  16. seleniumbase/console_scripts/sb_print.py +2 -0
  17. seleniumbase/console_scripts/sb_recorder.py +3 -2
  18. seleniumbase/core/browser_launcher.py +13 -27
  19. seleniumbase/core/capabilities_parser.py +2 -3
  20. seleniumbase/core/detect_b_ver.py +3 -4
  21. seleniumbase/core/jqc_helper.py +2 -4
  22. seleniumbase/core/mysql.py +1 -1
  23. seleniumbase/core/proxy_helper.py +65 -0
  24. seleniumbase/core/recorder_helper.py +1 -1
  25. seleniumbase/core/s3_manager.py +29 -23
  26. seleniumbase/core/session_helper.py +2 -6
  27. seleniumbase/core/settings_parser.py +2 -0
  28. seleniumbase/fixtures/base_case.py +31 -13
  29. seleniumbase/fixtures/constants.py +1 -1
  30. seleniumbase/fixtures/css_to_xpath.py +1 -2
  31. seleniumbase/fixtures/errors.py +2 -7
  32. seleniumbase/fixtures/js_utils.py +8 -16
  33. seleniumbase/fixtures/page_actions.py +3 -6
  34. seleniumbase/fixtures/page_utils.py +1 -1
  35. seleniumbase/fixtures/shared_utils.py +26 -79
  36. seleniumbase/fixtures/xpath_to_css.py +1 -3
  37. seleniumbase/plugins/base_plugin.py +1 -1
  38. seleniumbase/plugins/basic_test_info.py +1 -1
  39. seleniumbase/plugins/db_reporting_plugin.py +2 -2
  40. seleniumbase/plugins/driver_manager.py +2 -1
  41. seleniumbase/plugins/page_source.py +2 -4
  42. seleniumbase/plugins/pytest_plugin.py +9 -8
  43. seleniumbase/plugins/s3_logging_plugin.py +20 -9
  44. seleniumbase/plugins/sb_manager.py +2 -2
  45. seleniumbase/plugins/screen_shots.py +2 -2
  46. seleniumbase/plugins/selenium_plugin.py +5 -8
  47. seleniumbase/translate/translator.py +397 -396
  48. seleniumbase/undetected/__init__.py +17 -37
  49. seleniumbase/utilities/selenium_grid/grid_hub.py +2 -1
  50. seleniumbase/utilities/selenium_grid/grid_node.py +2 -1
  51. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/METADATA +8 -8
  52. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/RECORD +56 -56
  53. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/LICENSE +0 -0
  54. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/WHEEL +0 -0
  55. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/entry_points.txt +0 -0
  56. {seleniumbase-4.15.14.dist-info → seleniumbase-4.16.0.dist-info}/top_level.txt +0 -0
@@ -231,15 +231,14 @@ def main():
231
231
  url = "data:text/html,<p>%s<br><input>" % hello
232
232
 
233
233
  import_line = "from seleniumbase import BaseCase"
234
+ main_line = "BaseCase.main(__name__, __file__)"
234
235
  parent_class = "BaseCase"
235
- class_line = "class MyTestClass(BaseCase):"
236
236
  if language != "English":
237
237
  from seleniumbase.translate.master_dict import MD_F
238
238
 
239
239
  import_line = MD_F.get_import_line(language)
240
240
  parent_class = MD_F.get_lang_parent_class(language)
241
241
  class_line = "class %s(%s):" % (class_name, parent_class)
242
- main_line = "BaseCase.main(__name__, __file__)"
243
242
 
244
243
  data = []
245
244
  data.append("%s" % import_line)
@@ -194,8 +194,8 @@ def main():
194
194
  class_name = "MiClaseDePrueba"
195
195
 
196
196
  import_line = "from seleniumbase import BaseCase"
197
+ main_line = "BaseCase.main(__name__, __file__)"
197
198
  parent_class = "BaseCase"
198
- class_line = "class MyTestClass(BaseCase):"
199
199
  if language != "English":
200
200
  from seleniumbase.translate.master_dict import MD_F
201
201
 
@@ -223,6 +223,7 @@ def main():
223
223
 
224
224
  data = []
225
225
  data.append("%s" % import_line)
226
+ data.append("%s" % main_line)
226
227
  data.append("")
227
228
  data.append("")
228
229
  data.append("%s" % class_line)
@@ -262,6 +263,10 @@ def main():
262
263
  # Example: self.assert_true("Name" in self.get_title())
263
264
  line = new_line
264
265
  continue
266
+ if main_line in line:
267
+ new_main = "%s.main(__name__, __file__)" % parent_class
268
+ new_line = line.replace(main_line, new_main)
269
+ found_swap = True
265
270
  if found_swap:
266
271
  if new_line.endswith(" # noqa"): # Remove flake8 skip
267
272
  new_line = new_line[0 : -len(" # noqa")]
@@ -154,6 +154,8 @@ def main():
154
154
  w = 6
155
155
  if num_lines >= 1000:
156
156
  w = 7
157
+ if num_lines >= 10000:
158
+ w = 8
157
159
 
158
160
  if is_python_file:
159
161
  new_sb_lines = []
@@ -20,6 +20,7 @@ import subprocess
20
20
  import sys
21
21
  from seleniumbase import config as sb_config
22
22
  from seleniumbase.fixtures import page_utils
23
+ from seleniumbase.fixtures import shared_utils
23
24
 
24
25
  sb_config.rec_subprocess_p = None
25
26
  sb_config.rec_subprocess_used = False
@@ -179,7 +180,7 @@ def do_playback(file_name, use_chrome, window, demo_mode=False):
179
180
  )
180
181
  return
181
182
  command = "%s -m pytest %s -q -s" % (sys.executable, file_name)
182
- if "linux" in sys.platform:
183
+ if shared_utils.is_linux():
183
184
  command += " --gui"
184
185
  if not use_chrome:
185
186
  command += " --edge"
@@ -319,7 +320,7 @@ def end_program():
319
320
 
320
321
  def main():
321
322
  use_colors = True
322
- if "linux" in sys.platform:
323
+ if shared_utils.is_linux():
323
324
  use_colors = False
324
325
  c0, c1, c2, c3, c4, cr = set_colors(use_colors)
325
326
  message = ""
@@ -1,7 +1,6 @@
1
1
  import fasteners
2
2
  import logging
3
3
  import os
4
- import platform
5
4
  import re
6
5
  import shutil
7
6
  import subprocess
@@ -16,17 +15,17 @@ from selenium.webdriver.common.service import utils as service_utils
16
15
  from selenium.webdriver.edge.service import Service as EdgeService
17
16
  from selenium.webdriver.firefox.service import Service as FirefoxService
18
17
  from selenium.webdriver.safari.service import Service as SafariService
18
+ from seleniumbase import drivers # webdriver storage folder for SeleniumBase
19
+ from seleniumbase import extensions # browser extensions storage folder
19
20
  from seleniumbase.config import settings
20
21
  from seleniumbase.core import download_helper
21
22
  from seleniumbase.core import proxy_helper
22
23
  from seleniumbase.fixtures import constants
23
24
  from seleniumbase.fixtures import shared_utils
24
- from seleniumbase import drivers # webdriver storage folder for SeleniumBase
25
- from seleniumbase import extensions # browser extensions storage folder
26
25
 
27
26
  urllib3.disable_warnings()
28
27
  selenium4_or_newer = False
29
- if sys.version_info[0] == 3 and sys.version_info[1] >= 7:
28
+ if sys.version_info >= (3, 7):
30
29
  selenium4_or_newer = True
31
30
  from selenium.webdriver.common.options import ArgOptions
32
31
 
@@ -52,16 +51,6 @@ PROXY_ZIP_PATH = proxy_helper.PROXY_ZIP_PATH
52
51
  PROXY_ZIP_LOCK = proxy_helper.PROXY_ZIP_LOCK
53
52
  PROXY_DIR_PATH = proxy_helper.PROXY_DIR_PATH
54
53
  PROXY_DIR_LOCK = proxy_helper.PROXY_DIR_LOCK
55
- PLATFORM = sys.platform
56
- IS_ARM_MAC = False
57
- if (
58
- "darwin" in PLATFORM
59
- and (
60
- "arm" in platform.processor().lower()
61
- or "arm64" in platform.version().lower()
62
- )
63
- ):
64
- IS_ARM_MAC = True
65
54
  LOCAL_CHROMEDRIVER = None
66
55
  LOCAL_GECKODRIVER = None
67
56
  LOCAL_EDGEDRIVER = None
@@ -69,21 +58,17 @@ LOCAL_IEDRIVER = None
69
58
  LOCAL_HEADLESS_IEDRIVER = None
70
59
  LOCAL_OPERADRIVER = None
71
60
  LOCAL_UC_DRIVER = None
72
- IS_WINDOWS = False
73
- IS_LINUX = False
74
- IS_MAC = False
75
- if "darwin" in PLATFORM or "linux" in PLATFORM:
61
+ IS_ARM_MAC = shared_utils.is_arm_mac()
62
+ IS_MAC = shared_utils.is_mac()
63
+ IS_LINUX = shared_utils.is_linux()
64
+ IS_WINDOWS = shared_utils.is_windows()
65
+ if IS_MAC or IS_LINUX:
76
66
  LOCAL_CHROMEDRIVER = DRIVER_DIR + "/chromedriver"
77
67
  LOCAL_GECKODRIVER = DRIVER_DIR + "/geckodriver"
78
68
  LOCAL_EDGEDRIVER = DRIVER_DIR + "/msedgedriver"
79
69
  LOCAL_OPERADRIVER = DRIVER_DIR + "/operadriver"
80
70
  LOCAL_UC_DRIVER = DRIVER_DIR + "/uc_driver"
81
- if "darwin" in PLATFORM:
82
- IS_MAC = True
83
- elif "linux" in PLATFORM:
84
- IS_LINUX = True
85
- elif "win32" in PLATFORM or "win64" in PLATFORM or "x64" in PLATFORM:
86
- IS_WINDOWS = True
71
+ elif IS_WINDOWS:
87
72
  LOCAL_EDGEDRIVER = DRIVER_DIR + "/msedgedriver.exe"
88
73
  LOCAL_IEDRIVER = DRIVER_DIR + "/IEDriverServer.exe"
89
74
  LOCAL_HEADLESS_IEDRIVER = DRIVER_DIR + "/headless_ie_selenium.exe"
@@ -186,8 +171,8 @@ def uc_open(driver, url):
186
171
  and has_cf(requests_get(url).text)
187
172
  ):
188
173
  driver.execute_script('window.open("%s","_blank");' % url)
189
- time.sleep(2.75)
190
- driver.execute_script("window.close();")
174
+ driver.reconnect(2.65)
175
+ driver.close()
191
176
  driver.switch_to.window(driver.window_handles[-1])
192
177
  else:
193
178
  driver.open(url) # The original one
@@ -822,6 +807,7 @@ def _set_chrome_options(
822
807
  )
823
808
  ):
824
809
  chrome_options.add_argument("--disable-popup-blocking")
810
+ chrome_options.add_argument("--homepage=chrome://new-tab-page/")
825
811
  # Skip remaining options that trigger anti-bot services
826
812
  return chrome_options
827
813
  chrome_options.add_argument("--test-type")
@@ -1128,7 +1114,7 @@ def get_driver(
1128
1114
  "that has authentication! (If using a proxy server "
1129
1115
  "without auth, Chrome, Edge, or Firefox may be used.)"
1130
1116
  )
1131
- proxy_string = shared_utils.validate_proxy_string(proxy_string)
1117
+ proxy_string = proxy_helper.validate_proxy_string(proxy_string)
1132
1118
  if proxy_string and proxy_user and proxy_pass:
1133
1119
  proxy_auth = True
1134
1120
  elif proxy_pac_url:
@@ -9,16 +9,15 @@ def _analyze_ast(contents):
9
9
  except SyntaxError:
10
10
  pass
11
11
  try:
12
- # remove all comments
12
+ # Remove all comments
13
13
  contents = re.sub(re.compile(r"/\*.*?\*/", re.DOTALL), "", contents)
14
14
  contents = re.sub(re.compile(r"#.*?\n"), "", contents)
15
15
 
16
- # remove anything before dict declaration like: "caps = { ..."
16
+ # Remove anything before dict declaration like: "caps = { ..."
17
17
  match = re.match(r"^([^{]+)", contents)
18
18
  if match:
19
19
  contents = contents.replace(match.group(1), "")
20
20
 
21
- # and try again
22
21
  return ast.literal_eval(contents)
23
22
  except SyntaxError:
24
23
  pass
@@ -49,12 +49,11 @@ PATTERN = {
49
49
 
50
50
 
51
51
  def os_name():
52
- pl = sys.platform
53
- if pl == "linux" or pl == "linux2":
52
+ if "linux" in sys.platform:
54
53
  return OSType.LINUX
55
- elif pl == "darwin":
54
+ elif "darwin" in sys.platform:
56
55
  return OSType.MAC
57
- elif pl == "win32":
56
+ elif "win32" in sys.platform:
58
57
  return OSType.WIN
59
58
  else:
60
59
  raise Exception("Could not determine the OS type!")
@@ -1,7 +1,5 @@
1
- """
2
- This module contains methods for opening jquery-confirm boxes.
3
- These helper methods SHOULD NOT be called directly from tests.
4
- """
1
+ """This module contains methods for opening jquery-confirm boxes.
2
+ These helper methods SHOULD NOT be called directly from tests."""
5
3
  from seleniumbase.fixtures import constants
6
4
  from seleniumbase.fixtures import js_utils
7
5
 
@@ -1,4 +1,4 @@
1
- """Wrapper for MySQL DB functions."""
1
+ """Wrapper for MySQL DB functions"""
2
2
 
3
3
 
4
4
  class DatabaseManager:
@@ -1,6 +1,11 @@
1
1
  import os
2
+ import re
3
+ import warnings
2
4
  import zipfile
5
+ from seleniumbase.config import proxy_list
6
+ from seleniumbase.config import settings
3
7
  from seleniumbase.fixtures import constants
8
+ from seleniumbase.fixtures import page_utils
4
9
 
5
10
  DOWNLOADS_DIR = constants.Files.DOWNLOADS_FOLDER
6
11
  PROXY_ZIP_PATH = os.path.join(DOWNLOADS_DIR, "proxy.zip")
@@ -131,3 +136,63 @@ def remove_proxy_zip_if_present():
131
136
  os.remove(PROXY_ZIP_LOCK)
132
137
  except Exception:
133
138
  pass
139
+
140
+
141
+ def validate_proxy_string(proxy_string):
142
+ if proxy_string in proxy_list.PROXY_LIST.keys():
143
+ proxy_string = proxy_list.PROXY_LIST[proxy_string]
144
+ if not proxy_string:
145
+ return None
146
+ valid = False
147
+ val_ip = re.match(
148
+ r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$", proxy_string
149
+ )
150
+ if not val_ip:
151
+ if proxy_string.startswith("http://"):
152
+ proxy_string = proxy_string.split("http://")[1]
153
+ elif proxy_string.startswith("https://"):
154
+ proxy_string = proxy_string.split("https://")[1]
155
+ elif "://" in proxy_string:
156
+ if not proxy_string.startswith("socks4://") and not (
157
+ proxy_string.startswith("socks5://")
158
+ ):
159
+ proxy_string = proxy_string.split("://")[1]
160
+ chunks = proxy_string.split(":")
161
+ if len(chunks) == 2:
162
+ if re.match(r"^\d+$", chunks[1]):
163
+ if page_utils.is_valid_url("http://" + proxy_string):
164
+ valid = True
165
+ elif len(chunks) == 3:
166
+ if re.match(r"^\d+$", chunks[2]):
167
+ if page_utils.is_valid_url("http:" + ":".join(chunks[1:])):
168
+ if chunks[0] == "http":
169
+ valid = True
170
+ elif chunks[0] == "https":
171
+ valid = True
172
+ elif chunks[0] == "socks4":
173
+ valid = True
174
+ elif chunks[0] == "socks5":
175
+ valid = True
176
+ else:
177
+ proxy_string = val_ip.group()
178
+ valid = True
179
+ if not valid:
180
+ __display_proxy_warning(proxy_string)
181
+ proxy_string = None
182
+ return proxy_string
183
+
184
+
185
+ def __display_proxy_warning(proxy_string):
186
+ message = (
187
+ '\nWARNING: Proxy String ["%s"] is NOT in the expected '
188
+ '"ip_address:port" or "server:port" format, '
189
+ "(OR the key does not exist in "
190
+ "seleniumbase.config.proxy_list.PROXY_LIST)." % proxy_string
191
+ )
192
+ if settings.RAISE_INVALID_PROXY_STRING_EXCEPTION:
193
+ raise Exception(message)
194
+ else:
195
+ message += " *** DEFAULTING to NOT USING a Proxy Server! ***"
196
+ warnings.simplefilter("always", Warning) # See Warnings
197
+ warnings.warn(message, category=Warning, stacklevel=2)
198
+ warnings.simplefilter("default", Warning) # Set Default
@@ -1,4 +1,4 @@
1
- """Generating SeleniumBase Python code from the Recorder."""
1
+ """Generating SeleniumBase Python code from the Recorder"""
2
2
 
3
3
 
4
4
  def generate_sbase_code(srt_actions):
@@ -24,19 +24,20 @@ class S3LoggingBucket(object):
24
24
  )
25
25
  with pip_find_lock:
26
26
  try:
27
- from boto.s3.connection import S3Connection
27
+ import boto3
28
28
  except Exception:
29
- shared_utils.pip_install("boto", version="2.49.0")
30
- from boto.s3.connection import S3Connection
31
- self.conn = S3Connection(selenium_access_key, selenium_secret_key)
32
- self.bucket = self.conn.get_bucket(log_bucket)
29
+ shared_utils.pip_install("boto3")
30
+ import boto3
31
+ self.conn = boto3.Session(
32
+ aws_access_key_id=selenium_access_key,
33
+ aws_secret_access_key=selenium_secret_key,
34
+ )
35
+ self.bucket = log_bucket
33
36
  self.bucket_url = bucket_url
34
37
 
35
38
  def get_key(self, file_name):
36
- """Create a new Key instance with the given name."""
37
- from boto.s3.key import Key
38
-
39
- return Key(bucket=self.bucket, name=file_name)
39
+ """Create a new S3 connection instance with the given name."""
40
+ return self.conn.resource("s3").Object(self.bucket, file_name)
40
41
 
41
42
  def get_bucket(self):
42
43
  """Return the bucket being used."""
@@ -53,18 +54,19 @@ class S3LoggingBucket(object):
53
54
  content_type = "image/jpeg"
54
55
  elif file_name.endswith(".png"):
55
56
  content_type = "image/png"
56
- upload_key.set_contents_from_filename(
57
- file_path, headers={"Content-Type": content_type}
57
+ upload_key.Bucket().upload_file(
58
+ file_path,
59
+ file_name,
60
+ ExtraArgs={"ACL": "public-read", "ContentType": content_type},
58
61
  )
59
- upload_key.url = upload_key.generate_url(expires_in=3600).split("?")[0]
60
- try:
61
- upload_key.make_public()
62
- except Exception:
63
- pass
64
62
 
65
- def upload_index_file(self, test_address, timestamp):
63
+ def upload_index_file(
64
+ self, test_address, timestamp, data_path, save_data_to_logs
65
+ ):
66
66
  """Create an index.html file with links to all the log files
67
67
  that were just uploaded."""
68
+ import os
69
+
68
70
  global already_uploaded_files
69
71
  already_uploaded_files = list(set(already_uploaded_files))
70
72
  already_uploaded_files.sort()
@@ -76,15 +78,19 @@ class S3LoggingBucket(object):
76
78
  "<a href='" + self.bucket_url + ""
77
79
  "%s'>%s</a>" % (completed_file, completed_file)
78
80
  )
79
- index.set_contents_from_string(
80
- "<br>".join(index_str), headers={"Content-Type": "text/html"}
81
+ index_page = str("<br>".join(index_str))
82
+ save_data_to_logs(index_page, "index.html")
83
+ file_path = os.path.join(data_path, "index.html")
84
+ index.Bucket().upload_file(
85
+ file_path,
86
+ file_name,
87
+ ExtraArgs={"ACL": "public-read", "ContentType": "text/html"},
81
88
  )
82
- index.make_public()
83
89
  return "%s%s" % (self.bucket_url, file_name)
84
90
 
85
91
  def save_uploaded_file_names(self, files):
86
- """Keep a record of all file names that have been uploaded. Upload log
87
- files related to each test after its execution. Once done, use
88
- already_uploaded_files to create an index file."""
92
+ """Keep a record of all file names that have been uploaded.
93
+ Upload log files related to each test after its execution.
94
+ Once done, use already_uploaded_files to create an index file."""
89
95
  global already_uploaded_files
90
96
  already_uploaded_files.extend(files)
@@ -1,9 +1,5 @@
1
- import sys
2
1
  from seleniumbase import config as sb_config
3
-
4
- is_windows = False
5
- if sys.platform in ["win32", "win64", "x64"]:
6
- is_windows = True
2
+ from seleniumbase.fixtures import shared_utils
7
3
 
8
4
 
9
5
  def end_reused_class_session_as_needed():
@@ -14,7 +10,7 @@ def end_reused_class_session_as_needed():
14
10
  and sb_config.shared_driver
15
11
  ):
16
12
  if (
17
- not is_windows
13
+ not shared_utils.is_windows()
18
14
  or (
19
15
  hasattr(sb_config.shared_driver, "service")
20
16
  and sb_config.shared_driver.service.process
@@ -75,6 +75,8 @@ def set_settings(settings_file):
75
75
  settings.ARCHIVE_EXISTING_LOGS = override_settings[key]
76
76
  elif key == "ARCHIVE_EXISTING_DOWNLOADS":
77
77
  settings.ARCHIVE_EXISTING_DOWNLOADS = override_settings[key]
78
+ elif key == "SCREENSHOT_WITH_BACKGROUND":
79
+ settings.SCREENSHOT_WITH_BACKGROUND = override_settings[key]
78
80
  elif key == "SCREENSHOT_NAME":
79
81
  settings.SCREENSHOT_NAME = override_settings[key]
80
82
  elif key == "BASIC_INFO_NAME":
@@ -65,6 +65,7 @@ from seleniumbase.common.exceptions import (
65
65
  NotConnectedException,
66
66
  NotUsingChromeException,
67
67
  NotUsingChromiumException,
68
+ ProxyConnectionException,
68
69
  OutOfScopeException,
69
70
  VisualException,
70
71
  )
@@ -87,9 +88,7 @@ logging.getLogger("requests").setLevel(logging.ERROR)
87
88
  logging.getLogger("urllib3").setLevel(logging.ERROR)
88
89
  urllib3.disable_warnings()
89
90
  LOGGER.setLevel(logging.WARNING)
90
- is_windows = False
91
- if sys.platform in ["win32", "win64", "x64"]:
92
- is_windows = True
91
+ is_windows = shared_utils.is_windows()
93
92
  python3_11_or_newer = False
94
93
  if sys.version_info >= (3, 11):
95
94
  python3_11_or_newer = True
@@ -263,6 +262,7 @@ class BaseCase(unittest.TestCase):
263
262
  elif (
264
263
  "ERR_INTERNET_DISCONNECTED" in e.msg
265
264
  or "neterror?e=dnsNotFound" in e.msg
265
+ or "ERR_PROXY_CONNECTION_FAILED" in e.msg
266
266
  ):
267
267
  shared_utils.check_if_time_limit_exceeded()
268
268
  self.__check_browser()
@@ -274,8 +274,13 @@ class BaseCase(unittest.TestCase):
274
274
  "ERR_INTERNET_DISCONNECTED" in e2.msg
275
275
  or "neterror?e=dnsNotFound" in e2.msg
276
276
  ):
277
- message = "Internet unreachable!"
277
+ message = "ERR_INTERNET_DISCONNECTED: "
278
+ message += "Internet unreachable!"
278
279
  raise NotConnectedException(message)
280
+ elif "ERR_PROXY_CONNECTION_FAILED" in e2.msg:
281
+ message = "ERR_PROXY_CONNECTION_FAILED: "
282
+ message += "Internet unreachable and/or invalid proxy!"
283
+ raise ProxyConnectionException(message)
279
284
  else:
280
285
  raise
281
286
  elif "Timed out receiving message from renderer" in e.msg:
@@ -7266,6 +7271,11 @@ class BaseCase(unittest.TestCase):
7266
7271
  """Return True if the url is a valid url."""
7267
7272
  return page_utils.is_valid_url(url)
7268
7273
 
7274
+ def is_online(self):
7275
+ """Return True if connected to the Internet."""
7276
+ online = self.execute_script("return navigator.onLine;")
7277
+ return online
7278
+
7269
7279
  def is_chromium(self):
7270
7280
  """Return True if the browser is Chrome, Edge, or Opera."""
7271
7281
  self.__check_scope()
@@ -13676,11 +13686,9 @@ class BaseCase(unittest.TestCase):
13676
13686
  )
13677
13687
  from seleniumbase.core.testcase_manager import (
13678
13688
  ExecutionQueryPayload,
13679
- )
13680
- from seleniumbase.core.testcase_manager import (
13681
13689
  TestcaseDataPayload,
13690
+ TestcaseManager,
13682
13691
  )
13683
- from seleniumbase.core.testcase_manager import TestcaseManager
13684
13692
 
13685
13693
  self.execution_guid = str(uuid.uuid4())
13686
13694
  self.testcase_guid = None
@@ -14027,7 +14035,17 @@ class BaseCase(unittest.TestCase):
14027
14035
  ignore_test_time_limit=True,
14028
14036
  )
14029
14037
  try:
14030
- self.__last_page_screenshot = element.screenshot_as_base64
14038
+ if (
14039
+ hasattr(settings, "SCREENSHOT_WITH_BACKGROUND")
14040
+ and settings.SCREENSHOT_WITH_BACKGROUND
14041
+ ):
14042
+ self.__last_page_screenshot = (
14043
+ self.driver.get_screenshot_as_base64()
14044
+ )
14045
+ else:
14046
+ self.__last_page_screenshot = (
14047
+ element.screenshot_as_base64
14048
+ )
14031
14049
  except Exception:
14032
14050
  try:
14033
14051
  self.__last_page_screenshot = (
@@ -15178,16 +15196,16 @@ class BaseCase(unittest.TestCase):
15178
15196
  )
15179
15197
  uploaded_files.append(logfile_name)
15180
15198
  s3_bucket.save_uploaded_file_names(uploaded_files)
15181
- index_file = s3_bucket.upload_index_file(test_id, guid)
15182
- print("\n\n*** Log files uploaded: ***\n%s\n" % index_file)
15199
+ index_file = s3_bucket.upload_index_file(
15200
+ test_id, guid, self.data_path, self.save_data_to_logs
15201
+ )
15202
+ print("\n*** Log files uploaded: ***\n%s\n" % index_file)
15183
15203
  logging.info(
15184
- "\n\n*** Log files uploaded: ***\n%s\n" % index_file
15204
+ "\n*** Log files uploaded: ***\n%s\n" % index_file
15185
15205
  )
15186
15206
  if self.with_db_reporting:
15187
15207
  from seleniumbase.core.testcase_manager import (
15188
15208
  TestcaseDataPayload,
15189
- )
15190
- from seleniumbase.core.testcase_manager import (
15191
15209
  TestcaseManager,
15192
15210
  )
15193
15211
 
@@ -1,4 +1,4 @@
1
- """SeleniumBase constants are stored in this file."""
1
+ """SeleniumBase constants"""
2
2
  from seleniumbase.core import encoded_images
3
3
 
4
4
 
@@ -6,8 +6,7 @@ class ConvertibleToCssTranslator(GenericTranslator):
6
6
  """An implementation of :py:class:`cssselect.GenericTranslator` with
7
7
  XPath output that more readily converts back to CSS selectors.
8
8
  The simplified examples in https://devhints.io/xpath were used as a
9
- reference here.
10
- """
9
+ reference here."""
11
10
 
12
11
  def css_to_xpath(self, css, prefix="//"):
13
12
  return super().css_to_xpath(css, prefix)
@@ -1,28 +1,23 @@
1
- """
2
- SeleniumBase MySQL-related exceptions.
1
+ """SeleniumBase MySQL-related exceptions.
3
2
 
4
3
  This feature is DEPRECATED!
5
4
  Use self.skip() for skipping tests!
6
5
 
7
6
  Raising one of these in a test will cause the
8
7
  test-state to be logged appropriately in the DB
9
- for tests that use the SeleniumBase MySQL option.
10
- """
8
+ for tests that use the SeleniumBase MySQL option."""
11
9
 
12
10
 
13
11
  class BlockedTest(Exception):
14
12
  """Raise this to mark a test as Blocked in the DB."""
15
-
16
13
  pass
17
14
 
18
15
 
19
16
  class SkipTest(Exception):
20
17
  """Raise this to mark a test as Skipped in the DB."""
21
-
22
18
  pass
23
19
 
24
20
 
25
21
  class DeprecatedTest(Exception):
26
22
  """Raise this to mark a test as Deprecated in the DB."""
27
-
28
23
  pass
@@ -1,7 +1,4 @@
1
- """
2
- This module contains useful Javascript utility methods for base_case.py
3
- These helper methods SHOULD NOT be called directly from tests.
4
- """
1
+ """This module contains useful Javascript utility methods for BaseCase."""
5
2
  import re
6
3
  import requests
7
4
  import time
@@ -13,16 +10,14 @@ from seleniumbase.fixtures import constants
13
10
 
14
11
 
15
12
  def wait_for_ready_state_complete(driver, timeout=settings.LARGE_TIMEOUT):
16
- """
17
- The DOM (Document Object Model) has a property called "readyState".
13
+ """The DOM (Document Object Model) has a property called "readyState".
18
14
  When the value of this becomes "complete", page resources are considered
19
15
  fully loaded (although AJAX and other loads might still be happening).
20
16
  This method will wait until document.readyState == "complete".
21
17
  This may be redundant, as methods already wait for page elements to load.
22
18
  If the timeout is exceeded, the test will still continue
23
19
  because readyState == "interactive" may be good enough.
24
- (Previously, tests would fail immediately if exceeding the timeout.)
25
- """
20
+ (Previously, tests would fail immediately if exceeding the timeout.)"""
26
21
  if hasattr(settings, "SKIP_JS_WAITS") and settings.SKIP_JS_WAITS:
27
22
  return
28
23
  if sb_config.time_limit and not sb_config.recorder_mode:
@@ -157,8 +152,8 @@ def raise_unable_to_load_jquery_exception(driver):
157
152
 
158
153
 
159
154
  def activate_jquery(driver):
160
- """If "jQuery is not defined" on a website, use this method to activate it.
161
- This method is needed because jQuery is not always defined on web sites."""
155
+ # If "jQuery is not defined" on a website, use this method to activate it.
156
+ # This method is needed because jQuery is not always defined on web sites.
162
157
  try:
163
158
  # Let's first find out if jQuery is already defined.
164
159
  driver.execute_script("jQuery('html');")
@@ -191,8 +186,7 @@ def are_quotes_escaped(string):
191
186
 
192
187
 
193
188
  def escape_quotes_if_needed(string):
194
- """
195
- re.escape() works differently in Python 3.7.0 than earlier versions:
189
+ """re.escape() works differently in Python 3.7.0 than earlier versions:
196
190
 
197
191
  Python 3.6.5:
198
192
  >>> import re
@@ -215,10 +209,8 @@ def escape_quotes_if_needed(string):
215
209
 
216
210
 
217
211
  def is_in_frame(driver):
218
- """
219
- Returns True if the driver has switched to a frame.
220
- Returns False if the driver was on default content.
221
- """
212
+ # Returns True if the driver has switched to a frame.
213
+ # Returns False if the driver was on default content.
222
214
  in_basic_frame = driver.execute_script(
223
215
  """
224
216
  var frame = window.frameElement;