seleniumbase 4.15.15__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.
- sbase/__init__.py +1 -0
- seleniumbase/__init__.py +1 -0
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +12 -19
- seleniumbase/common/exceptions.py +5 -0
- seleniumbase/config/settings.py +7 -0
- seleniumbase/console_scripts/ReadMe.md +2 -2
- seleniumbase/console_scripts/run.py +5 -4
- seleniumbase/console_scripts/sb_behave_gui.py +6 -9
- seleniumbase/console_scripts/sb_caseplans.py +2 -5
- seleniumbase/console_scripts/sb_commander.py +5 -8
- seleniumbase/console_scripts/sb_install.py +43 -54
- seleniumbase/console_scripts/sb_print.py +2 -0
- seleniumbase/console_scripts/sb_recorder.py +3 -2
- seleniumbase/core/browser_launcher.py +13 -27
- seleniumbase/core/capabilities_parser.py +2 -3
- seleniumbase/core/detect_b_ver.py +3 -4
- seleniumbase/core/jqc_helper.py +2 -4
- seleniumbase/core/mysql.py +1 -1
- seleniumbase/core/proxy_helper.py +65 -0
- seleniumbase/core/recorder_helper.py +1 -1
- seleniumbase/core/s3_manager.py +29 -23
- seleniumbase/core/session_helper.py +2 -6
- seleniumbase/core/settings_parser.py +2 -0
- seleniumbase/fixtures/base_case.py +31 -13
- seleniumbase/fixtures/constants.py +1 -1
- seleniumbase/fixtures/css_to_xpath.py +1 -2
- seleniumbase/fixtures/errors.py +2 -7
- seleniumbase/fixtures/js_utils.py +8 -16
- seleniumbase/fixtures/page_actions.py +3 -6
- seleniumbase/fixtures/page_utils.py +1 -1
- seleniumbase/fixtures/shared_utils.py +26 -79
- seleniumbase/fixtures/xpath_to_css.py +1 -3
- seleniumbase/plugins/base_plugin.py +1 -1
- seleniumbase/plugins/basic_test_info.py +1 -1
- seleniumbase/plugins/db_reporting_plugin.py +2 -2
- seleniumbase/plugins/driver_manager.py +2 -1
- seleniumbase/plugins/page_source.py +2 -4
- seleniumbase/plugins/pytest_plugin.py +9 -8
- seleniumbase/plugins/s3_logging_plugin.py +20 -9
- seleniumbase/plugins/sb_manager.py +2 -2
- seleniumbase/plugins/screen_shots.py +2 -2
- seleniumbase/plugins/selenium_plugin.py +5 -8
- seleniumbase/translate/translator.py +397 -396
- seleniumbase/undetected/__init__.py +17 -37
- seleniumbase/utilities/selenium_grid/grid_hub.py +2 -1
- seleniumbase/utilities/selenium_grid/grid_node.py +2 -1
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/METADATA +7 -7
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/RECORD +53 -53
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/LICENSE +0 -0
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/WHEEL +0 -0
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/top_level.txt +0 -0
@@ -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
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
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
|
-
|
190
|
-
driver.
|
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 =
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
53
|
-
if pl == "linux" or pl == "linux2":
|
52
|
+
if "linux" in sys.platform:
|
54
53
|
return OSType.LINUX
|
55
|
-
elif
|
54
|
+
elif "darwin" in sys.platform:
|
56
55
|
return OSType.MAC
|
57
|
-
elif
|
56
|
+
elif "win32" in sys.platform:
|
58
57
|
return OSType.WIN
|
59
58
|
else:
|
60
59
|
raise Exception("Could not determine the OS type!")
|
seleniumbase/core/jqc_helper.py
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
"""
|
2
|
-
|
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
|
|
seleniumbase/core/mysql.py
CHANGED
@@ -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
|
seleniumbase/core/s3_manager.py
CHANGED
@@ -24,19 +24,20 @@ class S3LoggingBucket(object):
|
|
24
24
|
)
|
25
25
|
with pip_find_lock:
|
26
26
|
try:
|
27
|
-
|
27
|
+
import boto3
|
28
28
|
except Exception:
|
29
|
-
shared_utils.pip_install("
|
30
|
-
|
31
|
-
self.conn =
|
32
|
-
|
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
|
37
|
-
|
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.
|
57
|
-
file_path,
|
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(
|
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
|
-
|
80
|
-
|
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.
|
87
|
-
files related to each test after its execution.
|
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 =
|
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 = "
|
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
|
-
|
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(
|
15182
|
-
|
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
|
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
|
|
@@ -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)
|
seleniumbase/fixtures/errors.py
CHANGED
@@ -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
|
-
|
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
|
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;
|
@@ -1,12 +1,10 @@
|
|
1
|
-
"""
|
2
|
-
This module contains a set of methods that can be used for page loads and
|
3
|
-
for waiting for elements to appear on a page.
|
1
|
+
"""This module contains useful methods for waiting on elements to load.
|
4
2
|
|
5
|
-
These methods improve
|
3
|
+
These methods improve and expand on existing WebDriver commands.
|
6
4
|
Improvements include making WebDriver commands more robust and more reliable
|
7
5
|
by giving page elements enough time to load before taking action on them.
|
8
6
|
|
9
|
-
The default option for searching for elements is by
|
7
|
+
The default option for searching for elements is by "css selector".
|
10
8
|
This can be changed by overriding the "By" parameter from this import:
|
11
9
|
> from selenium.webdriver.common.by import By
|
12
10
|
Options are:
|
@@ -19,7 +17,6 @@ By.XPATH # "xpath"
|
|
19
17
|
By.TAG_NAME # "tag name"
|
20
18
|
By.PARTIAL_LINK_TEXT # "partial link text"
|
21
19
|
"""
|
22
|
-
|
23
20
|
import codecs
|
24
21
|
import os
|
25
22
|
import time
|