seleniumbase 4.33.5__py3-none-any.whl → 4.33.7__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/core/browser_launcher.py +104 -52
- seleniumbase/core/log_helper.py +18 -10
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/sb_cdp.py +86 -22
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/fixtures/base_case.py +61 -44
- seleniumbase/fixtures/js_utils.py +2 -0
- seleniumbase/fixtures/shared_utils.py +25 -0
- seleniumbase/plugins/pytest_plugin.py +47 -2
- seleniumbase/undetected/cdp_driver/element.py +4 -2
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/METADATA +2 -2
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/RECORD +17 -17
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/LICENSE +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/WHEEL +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.33.5.dist-info → seleniumbase-4.33.7.dist-info}/top_level.txt +0 -0
@@ -1451,7 +1451,7 @@ class BaseCase(unittest.TestCase):
|
|
1451
1451
|
return self.__is_shadow_element_enabled(selector)
|
1452
1452
|
return page_actions.is_element_enabled(self.driver, selector, by)
|
1453
1453
|
|
1454
|
-
def is_text_visible(self, text, selector="
|
1454
|
+
def is_text_visible(self, text, selector="body", by="css selector"):
|
1455
1455
|
"""Returns whether the text substring is visible in the element."""
|
1456
1456
|
self.wait_for_ready_state_complete()
|
1457
1457
|
time.sleep(0.01)
|
@@ -1460,7 +1460,7 @@ class BaseCase(unittest.TestCase):
|
|
1460
1460
|
return self.__is_shadow_text_visible(text, selector)
|
1461
1461
|
return page_actions.is_text_visible(self.driver, text, selector, by)
|
1462
1462
|
|
1463
|
-
def is_exact_text_visible(self, text, selector="
|
1463
|
+
def is_exact_text_visible(self, text, selector="body", by="css selector"):
|
1464
1464
|
"""Returns whether the text is exactly equal to the element text.
|
1465
1465
|
(Leading and trailing whitespace is ignored in the verification.)"""
|
1466
1466
|
self.wait_for_ready_state_complete()
|
@@ -1472,7 +1472,7 @@ class BaseCase(unittest.TestCase):
|
|
1472
1472
|
self.driver, text, selector, by
|
1473
1473
|
)
|
1474
1474
|
|
1475
|
-
def is_non_empty_text_visible(self, selector="
|
1475
|
+
def is_non_empty_text_visible(self, selector="body", by="css selector"):
|
1476
1476
|
"""Returns whether the element has any non-empty text visible.
|
1477
1477
|
Whitespace-only text is considered empty text."""
|
1478
1478
|
self.wait_for_ready_state_complete()
|
@@ -1842,7 +1842,7 @@ class BaseCase(unittest.TestCase):
|
|
1842
1842
|
elif self.slow_mode:
|
1843
1843
|
self.__slow_mode_pause_if_active()
|
1844
1844
|
|
1845
|
-
def get_text(self, selector="
|
1845
|
+
def get_text(self, selector="body", by="css selector", timeout=None):
|
1846
1846
|
self.__check_scope()
|
1847
1847
|
if not timeout:
|
1848
1848
|
timeout = settings.LARGE_TIMEOUT
|
@@ -2105,7 +2105,7 @@ class BaseCase(unittest.TestCase):
|
|
2105
2105
|
return property_value
|
2106
2106
|
|
2107
2107
|
def get_text_content(
|
2108
|
-
self, selector="
|
2108
|
+
self, selector="body", by="css selector", timeout=None
|
2109
2109
|
):
|
2110
2110
|
"""Returns the text that appears in the HTML for an element.
|
2111
2111
|
This is different from "self.get_text(selector, by="css selector")"
|
@@ -6093,7 +6093,7 @@ class BaseCase(unittest.TestCase):
|
|
6093
6093
|
if limit > 0 and count >= limit:
|
6094
6094
|
break
|
6095
6095
|
|
6096
|
-
def press_up_arrow(self, selector="
|
6096
|
+
def press_up_arrow(self, selector="body", times=1, by="css selector"):
|
6097
6097
|
"""Simulates pressing the UP Arrow on the keyboard.
|
6098
6098
|
By default, "html" will be used as the CSS Selector target.
|
6099
6099
|
You can specify how many times in-a-row the action happens."""
|
@@ -6115,7 +6115,7 @@ class BaseCase(unittest.TestCase):
|
|
6115
6115
|
if self.slow_mode:
|
6116
6116
|
time.sleep(0.1)
|
6117
6117
|
|
6118
|
-
def press_down_arrow(self, selector="
|
6118
|
+
def press_down_arrow(self, selector="body", times=1, by="css selector"):
|
6119
6119
|
"""Simulates pressing the DOWN Arrow on the keyboard.
|
6120
6120
|
By default, "html" will be used as the CSS Selector target.
|
6121
6121
|
You can specify how many times in-a-row the action happens."""
|
@@ -6137,7 +6137,7 @@ class BaseCase(unittest.TestCase):
|
|
6137
6137
|
if self.slow_mode:
|
6138
6138
|
time.sleep(0.1)
|
6139
6139
|
|
6140
|
-
def press_left_arrow(self, selector="
|
6140
|
+
def press_left_arrow(self, selector="body", times=1, by="css selector"):
|
6141
6141
|
"""Simulates pressing the LEFT Arrow on the keyboard.
|
6142
6142
|
By default, "html" will be used as the CSS Selector target.
|
6143
6143
|
You can specify how many times in-a-row the action happens."""
|
@@ -6159,7 +6159,7 @@ class BaseCase(unittest.TestCase):
|
|
6159
6159
|
if self.slow_mode:
|
6160
6160
|
time.sleep(0.1)
|
6161
6161
|
|
6162
|
-
def press_right_arrow(self, selector="
|
6162
|
+
def press_right_arrow(self, selector="body", times=1, by="css selector"):
|
6163
6163
|
"""Simulates pressing the RIGHT Arrow on the keyboard.
|
6164
6164
|
By default, "html" will be used as the CSS Selector target.
|
6165
6165
|
You can specify how many times in-a-row the action happens."""
|
@@ -7042,6 +7042,8 @@ class BaseCase(unittest.TestCase):
|
|
7042
7042
|
constants.PipInstall.FINDLOCK
|
7043
7043
|
)
|
7044
7044
|
with pip_find_lock:
|
7045
|
+
with suppress(Exception):
|
7046
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7045
7047
|
if sys.version_info < (3, 9):
|
7046
7048
|
# Fix bug in newer cryptography for Python 3.7 and 3.8:
|
7047
7049
|
# "pyo3_runtime.PanicException: Python API call failed"
|
@@ -7292,6 +7294,8 @@ class BaseCase(unittest.TestCase):
|
|
7292
7294
|
constants.PipInstall.FINDLOCK
|
7293
7295
|
)
|
7294
7296
|
with pip_find_lock:
|
7297
|
+
with suppress(Exception):
|
7298
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
7295
7299
|
try:
|
7296
7300
|
from PIL import Image, ImageDraw
|
7297
7301
|
except Exception:
|
@@ -7337,6 +7341,10 @@ class BaseCase(unittest.TestCase):
|
|
7337
7341
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7338
7342
|
)
|
7339
7343
|
with download_file_lock:
|
7344
|
+
with suppress(Exception):
|
7345
|
+
shared_utils.make_writable(
|
7346
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7347
|
+
)
|
7340
7348
|
if not destination_folder:
|
7341
7349
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
7342
7350
|
if not os.path.exists(destination_folder):
|
@@ -7357,6 +7365,10 @@ class BaseCase(unittest.TestCase):
|
|
7357
7365
|
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7358
7366
|
)
|
7359
7367
|
with download_file_lock:
|
7368
|
+
with suppress(Exception):
|
7369
|
+
shared_utils.make_writable(
|
7370
|
+
constants.MultiBrowser.DOWNLOAD_FILE_LOCK
|
7371
|
+
)
|
7360
7372
|
if not destination_folder:
|
7361
7373
|
destination_folder = constants.Files.DOWNLOADS_FOLDER
|
7362
7374
|
if not os.path.exists(destination_folder):
|
@@ -7462,6 +7474,8 @@ class BaseCase(unittest.TestCase):
|
|
7462
7474
|
constants.MultiBrowser.FILE_IO_LOCK
|
7463
7475
|
)
|
7464
7476
|
with file_io_lock:
|
7477
|
+
with suppress(Exception):
|
7478
|
+
shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
|
7465
7479
|
with open(fpath, "r") as f:
|
7466
7480
|
data = f.read().strip()
|
7467
7481
|
return data
|
@@ -9716,7 +9730,7 @@ class BaseCase(unittest.TestCase):
|
|
9716
9730
|
############
|
9717
9731
|
|
9718
9732
|
def wait_for_text_visible(
|
9719
|
-
self, text, selector="
|
9733
|
+
self, text, selector="body", by="css selector", timeout=None
|
9720
9734
|
):
|
9721
9735
|
self.__check_scope()
|
9722
9736
|
if not timeout:
|
@@ -9734,7 +9748,7 @@ class BaseCase(unittest.TestCase):
|
|
9734
9748
|
)
|
9735
9749
|
|
9736
9750
|
def wait_for_exact_text_visible(
|
9737
|
-
self, text, selector="
|
9751
|
+
self, text, selector="body", by="css selector", timeout=None
|
9738
9752
|
):
|
9739
9753
|
self.__check_scope()
|
9740
9754
|
if not timeout:
|
@@ -9751,7 +9765,7 @@ class BaseCase(unittest.TestCase):
|
|
9751
9765
|
)
|
9752
9766
|
|
9753
9767
|
def wait_for_non_empty_text_visible(
|
9754
|
-
self, selector="
|
9768
|
+
self, selector="body", by="css selector", timeout=None
|
9755
9769
|
):
|
9756
9770
|
"""Searches for any text in the element of the given selector.
|
9757
9771
|
Returns the element if it has visible text within the timeout.
|
@@ -9772,7 +9786,7 @@ class BaseCase(unittest.TestCase):
|
|
9772
9786
|
)
|
9773
9787
|
|
9774
9788
|
def wait_for_text(
|
9775
|
-
self, text, selector="
|
9789
|
+
self, text, selector="body", by="css selector", timeout=None
|
9776
9790
|
):
|
9777
9791
|
"""The shorter version of wait_for_text_visible()"""
|
9778
9792
|
self.__check_scope()
|
@@ -9785,7 +9799,7 @@ class BaseCase(unittest.TestCase):
|
|
9785
9799
|
)
|
9786
9800
|
|
9787
9801
|
def wait_for_exact_text(
|
9788
|
-
self, text, selector="
|
9802
|
+
self, text, selector="body", by="css selector", timeout=None
|
9789
9803
|
):
|
9790
9804
|
"""The shorter version of wait_for_exact_text_visible()"""
|
9791
9805
|
self.__check_scope()
|
@@ -9798,7 +9812,7 @@ class BaseCase(unittest.TestCase):
|
|
9798
9812
|
)
|
9799
9813
|
|
9800
9814
|
def wait_for_non_empty_text(
|
9801
|
-
self, selector="
|
9815
|
+
self, selector="body", by="css selector", timeout=None
|
9802
9816
|
):
|
9803
9817
|
"""The shorter version of wait_for_non_empty_text_visible()"""
|
9804
9818
|
self.__check_scope()
|
@@ -9811,7 +9825,7 @@ class BaseCase(unittest.TestCase):
|
|
9811
9825
|
)
|
9812
9826
|
|
9813
9827
|
def find_text(
|
9814
|
-
self, text, selector="
|
9828
|
+
self, text, selector="body", by="css selector", timeout=None
|
9815
9829
|
):
|
9816
9830
|
"""Same as wait_for_text_visible() - returns the element"""
|
9817
9831
|
self.__check_scope()
|
@@ -9824,7 +9838,7 @@ class BaseCase(unittest.TestCase):
|
|
9824
9838
|
)
|
9825
9839
|
|
9826
9840
|
def find_exact_text(
|
9827
|
-
self, text, selector="
|
9841
|
+
self, text, selector="body", by="css selector", timeout=None
|
9828
9842
|
):
|
9829
9843
|
"""Same as wait_for_exact_text_visible() - returns the element"""
|
9830
9844
|
self.__check_scope()
|
@@ -9837,7 +9851,7 @@ class BaseCase(unittest.TestCase):
|
|
9837
9851
|
)
|
9838
9852
|
|
9839
9853
|
def find_non_empty_text(
|
9840
|
-
self, selector="
|
9854
|
+
self, selector="body", by="css selector", timeout=None
|
9841
9855
|
):
|
9842
9856
|
"""Same as wait_for_non_empty_text_visible() - returns the element"""
|
9843
9857
|
self.__check_scope()
|
@@ -9850,7 +9864,7 @@ class BaseCase(unittest.TestCase):
|
|
9850
9864
|
)
|
9851
9865
|
|
9852
9866
|
def assert_text_visible(
|
9853
|
-
self, text, selector="
|
9867
|
+
self, text, selector="body", by="css selector", timeout=None
|
9854
9868
|
):
|
9855
9869
|
"""Same as assert_text()"""
|
9856
9870
|
self.__check_scope()
|
@@ -9861,7 +9875,7 @@ class BaseCase(unittest.TestCase):
|
|
9861
9875
|
return self.assert_text(text, selector, by=by, timeout=timeout)
|
9862
9876
|
|
9863
9877
|
def assert_text(
|
9864
|
-
self, text, selector="
|
9878
|
+
self, text, selector="body", by="css selector", timeout=None
|
9865
9879
|
):
|
9866
9880
|
"""Similar to wait_for_text_visible()
|
9867
9881
|
Raises an exception if the element or the text is not found.
|
@@ -9931,7 +9945,7 @@ class BaseCase(unittest.TestCase):
|
|
9931
9945
|
return True
|
9932
9946
|
|
9933
9947
|
def assert_exact_text(
|
9934
|
-
self, text, selector="
|
9948
|
+
self, text, selector="body", by="css selector", timeout=None
|
9935
9949
|
):
|
9936
9950
|
"""Similar to assert_text(), but the text must be exact,
|
9937
9951
|
rather than exist as a subset of the full text.
|
@@ -9978,7 +9992,7 @@ class BaseCase(unittest.TestCase):
|
|
9978
9992
|
return True
|
9979
9993
|
|
9980
9994
|
def assert_non_empty_text(
|
9981
|
-
self, selector="
|
9995
|
+
self, selector="body", by="css selector", timeout=None
|
9982
9996
|
):
|
9983
9997
|
"""Assert that the element has any non-empty text visible.
|
9984
9998
|
Raises an exception if the element has no text within the timeout.
|
@@ -10265,7 +10279,7 @@ class BaseCase(unittest.TestCase):
|
|
10265
10279
|
############
|
10266
10280
|
|
10267
10281
|
def wait_for_text_not_visible(
|
10268
|
-
self, text, selector="
|
10282
|
+
self, text, selector="body", by="css selector", timeout=None
|
10269
10283
|
):
|
10270
10284
|
self.__check_scope()
|
10271
10285
|
if not timeout:
|
@@ -10278,7 +10292,7 @@ class BaseCase(unittest.TestCase):
|
|
10278
10292
|
)
|
10279
10293
|
|
10280
10294
|
def wait_for_exact_text_not_visible(
|
10281
|
-
self, text, selector="
|
10295
|
+
self, text, selector="body", by="css selector", timeout=None
|
10282
10296
|
):
|
10283
10297
|
self.__check_scope()
|
10284
10298
|
if not timeout:
|
@@ -10291,7 +10305,7 @@ class BaseCase(unittest.TestCase):
|
|
10291
10305
|
)
|
10292
10306
|
|
10293
10307
|
def assert_text_not_visible(
|
10294
|
-
self, text, selector="
|
10308
|
+
self, text, selector="body", by="css selector", timeout=None
|
10295
10309
|
):
|
10296
10310
|
"""Similar to wait_for_text_not_visible()
|
10297
10311
|
Raises an exception if the text is still visible after timeout.
|
@@ -10312,7 +10326,7 @@ class BaseCase(unittest.TestCase):
|
|
10312
10326
|
return True
|
10313
10327
|
|
10314
10328
|
def assert_exact_text_not_visible(
|
10315
|
-
self, text, selector="
|
10329
|
+
self, text, selector="body", by="css selector", timeout=None
|
10316
10330
|
):
|
10317
10331
|
"""Similar to wait_for_exact_text_not_visible()
|
10318
10332
|
Raises an exception if the exact text is still visible after timeout.
|
@@ -11069,7 +11083,7 @@ class BaseCase(unittest.TestCase):
|
|
11069
11083
|
return False
|
11070
11084
|
|
11071
11085
|
def deferred_assert_text(
|
11072
|
-
self, text, selector="
|
11086
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11073
11087
|
):
|
11074
11088
|
"""A non-terminating assertion for text from an element on a page.
|
11075
11089
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11105,7 +11119,7 @@ class BaseCase(unittest.TestCase):
|
|
11105
11119
|
return False
|
11106
11120
|
|
11107
11121
|
def deferred_assert_exact_text(
|
11108
|
-
self, text, selector="
|
11122
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11109
11123
|
):
|
11110
11124
|
"""A non-terminating assertion for exact text from an element.
|
11111
11125
|
Failures will be saved until the process_deferred_asserts()
|
@@ -11144,7 +11158,7 @@ class BaseCase(unittest.TestCase):
|
|
11144
11158
|
|
11145
11159
|
def deferred_assert_non_empty_text(
|
11146
11160
|
self,
|
11147
|
-
selector="
|
11161
|
+
selector="body",
|
11148
11162
|
by="css selector",
|
11149
11163
|
timeout=None,
|
11150
11164
|
fs=False,
|
@@ -11264,7 +11278,7 @@ class BaseCase(unittest.TestCase):
|
|
11264
11278
|
)
|
11265
11279
|
|
11266
11280
|
def delayed_assert_text(
|
11267
|
-
self, text, selector="
|
11281
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11268
11282
|
):
|
11269
11283
|
"""Same as self.deferred_assert_text()"""
|
11270
11284
|
return self.deferred_assert_text(
|
@@ -11272,7 +11286,7 @@ class BaseCase(unittest.TestCase):
|
|
11272
11286
|
)
|
11273
11287
|
|
11274
11288
|
def delayed_assert_exact_text(
|
11275
|
-
self, text, selector="
|
11289
|
+
self, text, selector="body", by="css selector", timeout=None, fs=False
|
11276
11290
|
):
|
11277
11291
|
"""Same as self.deferred_assert_exact_text()"""
|
11278
11292
|
return self.deferred_assert_exact_text(
|
@@ -11281,7 +11295,7 @@ class BaseCase(unittest.TestCase):
|
|
11281
11295
|
|
11282
11296
|
def delayed_assert_non_empty_text(
|
11283
11297
|
self,
|
11284
|
-
selector="
|
11298
|
+
selector="body",
|
11285
11299
|
by="css selector",
|
11286
11300
|
timeout=None,
|
11287
11301
|
fs=False,
|
@@ -14057,19 +14071,12 @@ class BaseCase(unittest.TestCase):
|
|
14057
14071
|
with pip_find_lock:
|
14058
14072
|
pass
|
14059
14073
|
except Exception:
|
14060
|
-
#
|
14061
|
-
|
14062
|
-
|
14063
|
-
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
14064
|
-
os.chmod(constants.PipInstall.FINDLOCK, mode)
|
14065
|
-
try:
|
14066
|
-
with pip_find_lock:
|
14067
|
-
pass
|
14068
|
-
except Exception:
|
14069
|
-
# Since missing permissions, skip the locks
|
14070
|
-
self.__activate_virtual_display()
|
14071
|
-
return
|
14074
|
+
# Since missing permissions, skip the locks
|
14075
|
+
self.__activate_virtual_display()
|
14076
|
+
return
|
14072
14077
|
with pip_find_lock: # Prevent issues with multiple processes
|
14078
|
+
with suppress(Exception):
|
14079
|
+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
|
14073
14080
|
self.__activate_virtual_display()
|
14074
14081
|
|
14075
14082
|
def __ad_block_as_needed(self):
|
@@ -15091,6 +15098,10 @@ class BaseCase(unittest.TestCase):
|
|
15091
15098
|
if self.dashboard:
|
15092
15099
|
if self._multithreaded:
|
15093
15100
|
with self.dash_lock:
|
15101
|
+
with suppress(Exception):
|
15102
|
+
shared_utils.make_writable(
|
15103
|
+
constants.Dashboard.LOCKFILE
|
15104
|
+
)
|
15094
15105
|
if not self._dash_initialized:
|
15095
15106
|
sb_config._dashboard_initialized = True
|
15096
15107
|
self._dash_initialized = True
|
@@ -15650,6 +15661,8 @@ class BaseCase(unittest.TestCase):
|
|
15650
15661
|
constants.Dashboard.LOCKFILE
|
15651
15662
|
)
|
15652
15663
|
with self.dash_lock:
|
15664
|
+
with suppress(Exception):
|
15665
|
+
shared_utils.make_writable(constants.Dashboard.LOCKFILE)
|
15653
15666
|
self.__process_dashboard(has_exception, init)
|
15654
15667
|
else:
|
15655
15668
|
self.__process_dashboard(has_exception, init)
|
@@ -16419,6 +16432,10 @@ class BaseCase(unittest.TestCase):
|
|
16419
16432
|
if self.dashboard:
|
16420
16433
|
if self._multithreaded:
|
16421
16434
|
with self.dash_lock:
|
16435
|
+
with suppress(Exception):
|
16436
|
+
shared_utils.make_writable(
|
16437
|
+
constants.Dashboard.LOCKFILE
|
16438
|
+
)
|
16422
16439
|
self.__process_dashboard(has_exception)
|
16423
16440
|
else:
|
16424
16441
|
self.__process_dashboard(has_exception)
|
@@ -1188,6 +1188,8 @@ def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur):
|
|
1188
1188
|
def get_active_element_css(driver):
|
1189
1189
|
from seleniumbase.js_code import active_css_js
|
1190
1190
|
|
1191
|
+
if shared_utils.is_cdp_swap_needed(driver):
|
1192
|
+
return driver.cdp.get_active_element_css()
|
1191
1193
|
return execute_script(driver, active_css_js.get_active_element_css)
|
1192
1194
|
|
1193
1195
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""Shared utility methods"""
|
2
2
|
import colorama
|
3
3
|
import os
|
4
|
+
import pathlib
|
4
5
|
import platform
|
5
6
|
import sys
|
6
7
|
import time
|
@@ -128,6 +129,30 @@ def is_chrome_130_or_newer(self, binary_location=None):
|
|
128
129
|
return False
|
129
130
|
|
130
131
|
|
132
|
+
def make_dir_files_writable(dir_path):
|
133
|
+
# Make all files in the given directory writable.
|
134
|
+
for file_path in pathlib.Path(dir_path).glob("*"):
|
135
|
+
if file_path.is_file():
|
136
|
+
mode = os.stat(file_path).st_mode
|
137
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
138
|
+
with suppress(Exception):
|
139
|
+
os.chmod(file_path, mode)
|
140
|
+
|
141
|
+
|
142
|
+
def make_writable(file_path):
|
143
|
+
# Set permissions to: "If you can read it, you can write it."
|
144
|
+
mode = os.stat(file_path).st_mode
|
145
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
146
|
+
os.chmod(file_path, mode)
|
147
|
+
|
148
|
+
|
149
|
+
def make_executable(file_path):
|
150
|
+
# Set permissions to: "If you can read it, you can execute it."
|
151
|
+
mode = os.stat(file_path).st_mode
|
152
|
+
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
153
|
+
os.chmod(file_path, mode)
|
154
|
+
|
155
|
+
|
131
156
|
def format_exc(exception, message):
|
132
157
|
"""Formats an exception message to make the output cleaner."""
|
133
158
|
from selenium.common.exceptions import ElementNotVisibleException
|
@@ -2143,6 +2143,9 @@ def _perform_pytest_unconfigure_(config):
|
|
2143
2143
|
log_helper.archive_logs_if_set(
|
2144
2144
|
constants.Logs.LATEST + "/", sb_config.archive_logs
|
2145
2145
|
)
|
2146
|
+
if os.path.exists("./assets/"): # Used by pytest-html reports
|
2147
|
+
with suppress(Exception):
|
2148
|
+
shared_utils.make_dir_files_writable("./assets/")
|
2146
2149
|
log_helper.clear_empty_logs()
|
2147
2150
|
# Dashboard post-processing: Disable time-based refresh and stamp complete
|
2148
2151
|
if not hasattr(sb_config, "dashboard") or not sb_config.dashboard:
|
@@ -2207,8 +2210,28 @@ def _perform_pytest_unconfigure_(config):
|
|
2207
2210
|
)
|
2208
2211
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2209
2212
|
f.write(the_html_r) # Finalize the HTML report
|
2213
|
+
with suppress(Exception):
|
2214
|
+
shared_utils.make_writable(html_report_path)
|
2210
2215
|
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2211
|
-
f.write(the_html_r) # Finalize the HTML report
|
2216
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2217
|
+
with suppress(Exception):
|
2218
|
+
shared_utils.make_writable(html_report_path_copy)
|
2219
|
+
assets_style = "./assets/style.css"
|
2220
|
+
if os.path.exists(assets_style):
|
2221
|
+
html_style = None
|
2222
|
+
with open(assets_style, "r", encoding="utf-8") as f:
|
2223
|
+
html_style = f.read()
|
2224
|
+
if html_style:
|
2225
|
+
html_style = html_style.replace("top: -50px;", "top: 2px;")
|
2226
|
+
html_style = html_style.replace("+ 50px)", "+ 40px)")
|
2227
|
+
html_style = html_style.replace("ht: 240px;", "ht: 228px;")
|
2228
|
+
html_style = html_style.replace(
|
2229
|
+
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
2230
|
+
)
|
2231
|
+
with open(assets_style, "w", encoding="utf-8") as f:
|
2232
|
+
f.write(html_style)
|
2233
|
+
with suppress(Exception):
|
2234
|
+
shared_utils.make_writable(assets_style)
|
2212
2235
|
# Done with "pytest_unconfigure" unless using the Dashboard
|
2213
2236
|
return
|
2214
2237
|
stamp = ""
|
@@ -2290,6 +2313,24 @@ def _perform_pytest_unconfigure_(config):
|
|
2290
2313
|
)
|
2291
2314
|
with open(dashboard_path, "w", encoding="utf-8") as f:
|
2292
2315
|
f.write(the_html_d) # Finalize the dashboard
|
2316
|
+
with suppress(Exception):
|
2317
|
+
shared_utils.make_writable(dashboard_path)
|
2318
|
+
assets_style = "./assets/style.css"
|
2319
|
+
if os.path.exists(assets_style):
|
2320
|
+
html_style = None
|
2321
|
+
with open(assets_style, "r", encoding="utf-8") as f:
|
2322
|
+
html_style = f.read()
|
2323
|
+
if html_style:
|
2324
|
+
html_style = html_style.replace("top: -50px;", "top: 2px;")
|
2325
|
+
html_style = html_style.replace("+ 50px)", "+ 40px)")
|
2326
|
+
html_style = html_style.replace("ht: 240px;", "ht: 228px;")
|
2327
|
+
html_style = html_style.replace(
|
2328
|
+
"- 80px);", "- 80px);\n margin-bottom: -42px;"
|
2329
|
+
)
|
2330
|
+
with open(assets_style, "w", encoding="utf-8") as f:
|
2331
|
+
f.write(html_style)
|
2332
|
+
with suppress(Exception):
|
2333
|
+
shared_utils.make_writable(assets_style)
|
2293
2334
|
# Part 2: Appending a pytest html report with dashboard data
|
2294
2335
|
html_report_path = None
|
2295
2336
|
if sb_config._html_report_name:
|
@@ -2370,8 +2411,12 @@ def _perform_pytest_unconfigure_(config):
|
|
2370
2411
|
)
|
2371
2412
|
with open(html_report_path, "w", encoding="utf-8") as f:
|
2372
2413
|
f.write(the_html_r) # Finalize the HTML report
|
2414
|
+
with suppress(Exception):
|
2415
|
+
shared_utils.make_writable(html_report_path)
|
2373
2416
|
with open(html_report_path_copy, "w", encoding="utf-8") as f:
|
2374
|
-
f.write(the_html_r) # Finalize the HTML report
|
2417
|
+
f.write(the_html_r) # Finalize the HTML report copy
|
2418
|
+
with suppress(Exception):
|
2419
|
+
shared_utils.make_writable(html_report_path_copy)
|
2375
2420
|
except KeyboardInterrupt:
|
2376
2421
|
pass
|
2377
2422
|
except Exception:
|
@@ -883,6 +883,8 @@ class Element:
|
|
883
883
|
self,
|
884
884
|
duration: typing.Union[float, int] = 0.5,
|
885
885
|
color: typing.Optional[str] = "EE4488",
|
886
|
+
x_offset: typing.Union[float, int] = 0,
|
887
|
+
y_offset: typing.Union[float, int] = 0,
|
886
888
|
):
|
887
889
|
"""
|
888
890
|
Displays for a short time a red dot on the element.
|
@@ -910,8 +912,8 @@ class Element:
|
|
910
912
|
"width:8px;height:8px;border-radius:50%;background:#{};"
|
911
913
|
"animation:show-pointer-ani {:.2f}s ease 1;"
|
912
914
|
).format(
|
913
|
-
pos.center[0] - 4, # -4 to account for
|
914
|
-
pos.center[1] - 4,
|
915
|
+
pos.center[0] + x_offset - 4, # -4 to account for the circle
|
916
|
+
pos.center[1] + y_offset - 4, # -4 to account for the circle
|
915
917
|
color,
|
916
918
|
duration,
|
917
919
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: seleniumbase
|
3
|
-
Version: 4.33.
|
3
|
+
Version: 4.33.7
|
4
4
|
Summary: A complete web automation framework for end-to-end testing.
|
5
5
|
Home-page: https://github.com/seleniumbase/SeleniumBase
|
6
6
|
Author: Michael Mintz
|
@@ -126,7 +126,7 @@ Requires-Dist: allure-python-commons>=2.13.5; extra == "allure"
|
|
126
126
|
Requires-Dist: allure-behave>=2.13.5; extra == "allure"
|
127
127
|
Provides-Extra: coverage
|
128
128
|
Requires-Dist: coverage>=7.6.1; python_version < "3.9" and extra == "coverage"
|
129
|
-
Requires-Dist: coverage>=7.6.
|
129
|
+
Requires-Dist: coverage>=7.6.9; python_version >= "3.9" and extra == "coverage"
|
130
130
|
Requires-Dist: pytest-cov>=5.0.0; python_version < "3.9" and extra == "coverage"
|
131
131
|
Requires-Dist: pytest-cov>=6.0.0; python_version >= "3.9" and extra == "coverage"
|
132
132
|
Provides-Extra: flake8
|
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
|
|
3
3
|
sbase/steps.py,sha256=_WvAjydKqZfTdnZW9LPKkRty-g-lfdUPmLqnZj6ulcs,43013
|
4
4
|
seleniumbase/__init__.py,sha256=OtJh8nGKL4xtZpw8KPqmn7Q6R-86t4cWUDyVF5MbMTo,2398
|
5
5
|
seleniumbase/__main__.py,sha256=dn1p6dgCchmcH1zzTzzQvFwwdQQqnTGH6ULV9m4hv24,654
|
6
|
-
seleniumbase/__version__.py,sha256=
|
6
|
+
seleniumbase/__version__.py,sha256=nUNoxjUDcXHP7bgCzQttf4Edyro2DVTDgt8rIwb4KXs,46
|
7
7
|
seleniumbase/behave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
seleniumbase/behave/behave_helper.py,sha256=elkl8P9eLulRAioLstE9baYNM9N_PHBmAOcajX-pH_Y,24198
|
9
9
|
seleniumbase/behave/behave_sb.py,sha256=-hza7Nx2U41mSObYiPMi48v3JlPh3sJO3yzP0kqZ1Gk,59174
|
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
|
|
36
36
|
seleniumbase/console_scripts/sb_recorder.py,sha256=fnHb5-kh11Hit-E9Ha-e4QXzqLcZvtij6mb5qNd4B1Q,11032
|
37
37
|
seleniumbase/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
38
|
seleniumbase/core/application_manager.py,sha256=e_0sjtI8cjY5BNyZj1QBR0j6_oCScxGmSXYEpcYwuZE,576
|
39
|
-
seleniumbase/core/browser_launcher.py,sha256=
|
39
|
+
seleniumbase/core/browser_launcher.py,sha256=0J5J7kXG30aptlPQ3JdFcu8-U4lC_Y6U_47kkHbyKoo,224666
|
40
40
|
seleniumbase/core/capabilities_parser.py,sha256=meIS2uHapTCq2ldfNAToC7r0cKmZDRXuYNKExM1GHDY,6038
|
41
41
|
seleniumbase/core/colored_traceback.py,sha256=DrRWfg7XEnKcgY59Xj7Jdk09H-XqHYBSUpB-DiZt6iY,2020
|
42
42
|
seleniumbase/core/create_db_tables.sql,sha256=VWPtrdiW_HQ6yETHjqTu-VIrTwvd8I8o1NfBeaVSHpU,972
|
@@ -44,17 +44,17 @@ seleniumbase/core/detect_b_ver.py,sha256=RxeGRMbBUTMrXh5KsS1P1SH7eEKYbzL1vQw1gTd
|
|
44
44
|
seleniumbase/core/download_helper.py,sha256=qSR54kQISucF4RQaLCOuuerSu6DR41juGi_30HVvWYY,2943
|
45
45
|
seleniumbase/core/encoded_images.py,sha256=rDKJ4cNJSuKiRcFViYU7bjyTS9_moI57gUPRXVg3u2k,14209
|
46
46
|
seleniumbase/core/jqc_helper.py,sha256=2DDQr9Q2jSSZqFzX588jLlUM9oJvyrRWq2aORSIPUdI,10322
|
47
|
-
seleniumbase/core/log_helper.py,sha256=
|
47
|
+
seleniumbase/core/log_helper.py,sha256=N0YbsRy8sEoGQu4BjiAJHC5mK_ydl0YLgRp6jAcwwos,22987
|
48
48
|
seleniumbase/core/mysql.py,sha256=8Fzj3p5dhtDWfMpFqFYxpSwa9s1UltiHsWJ56_aPOqk,3993
|
49
|
-
seleniumbase/core/proxy_helper.py,sha256=
|
49
|
+
seleniumbase/core/proxy_helper.py,sha256=kZnfkflB3XhuL2h-3inmx3UOLS8VAZ385BGCc4H8TvU,8267
|
50
50
|
seleniumbase/core/recorder_helper.py,sha256=fNGjbapXmEsht54x1o6Igk198QdnPxDDnjUOzQxNhNQ,25055
|
51
51
|
seleniumbase/core/report_helper.py,sha256=AIl6Qava2yW1uSzbLpJBlPlYDz0KE-rVhogh8hsGWBo,12201
|
52
52
|
seleniumbase/core/s3_manager.py,sha256=bkeI8I4y19ebWuQG1oEZV5qJbotC6eN8vin31OCNWJk,3521
|
53
|
-
seleniumbase/core/sb_cdp.py,sha256=
|
53
|
+
seleniumbase/core/sb_cdp.py,sha256=Z2do1FqwfFAK-xgrZ6f_-wTMf3DSbI-ShHRZ34nFy5w,70437
|
54
54
|
seleniumbase/core/sb_driver.py,sha256=NGa4adi8OAi2WFtFkEguXg3JCd1p-JuZweIpGNifEfU,13488
|
55
55
|
seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
|
56
56
|
seleniumbase/core/settings_parser.py,sha256=KokVXpCiGZhJ-D4Bo-hizPz5r-iefzWoiTANu9zNaq4,7504
|
57
|
-
seleniumbase/core/style_sheet.py,sha256=
|
57
|
+
seleniumbase/core/style_sheet.py,sha256=QsfTBtgedfM3uTqgxtd53bhq202p9fwLMbFl9mPZgVg,11892
|
58
58
|
seleniumbase/core/testcase_manager.py,sha256=TblCfo8Zfap1Bayip-qTu9gqT-KALSwXAX4awBpnEHg,4633
|
59
59
|
seleniumbase/core/tour_helper.py,sha256=kj2cz-DGKlw9SX3tWnVp-snpk6Flvqj81-xmKdKDtg0,42555
|
60
60
|
seleniumbase/core/visual_helper.py,sha256=Dj5iJKw-bT_3e6KDqMf0sJi7xs_D96yqLcNc8fqhrjI,3408
|
@@ -65,14 +65,14 @@ seleniumbase/extensions/disable_csp.zip,sha256=YMifIIgEBiLrEFrS1sfW4Exh4br1V4oK1
|
|
65
65
|
seleniumbase/extensions/recorder.zip,sha256=OOyzF-Ize2cSRu1CqhzSAq5vusI9hqLLd2OIApUHesI,11918
|
66
66
|
seleniumbase/extensions/sbase_ext.zip,sha256=3s1N8zrVaMz8RQEOIoBzC3KDjtmHwVZRvVsX25Odr_s,8175
|
67
67
|
seleniumbase/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
68
|
-
seleniumbase/fixtures/base_case.py,sha256=
|
68
|
+
seleniumbase/fixtures/base_case.py,sha256=6MVQDcQ8woA3sis2hH6epDaVNjefsd2m1xzjJn9mugs,718550
|
69
69
|
seleniumbase/fixtures/constants.py,sha256=e1LppavlrAcI4XBJMq7u5j8SffaQ7SPQps1y0YvZYfY,13649
|
70
70
|
seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
|
71
71
|
seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
|
72
|
-
seleniumbase/fixtures/js_utils.py,sha256=
|
72
|
+
seleniumbase/fixtures/js_utils.py,sha256=asZJ0LDFv2BPQOzUVKK_9ie8ToGcmFousDnGdb3Vabg,51534
|
73
73
|
seleniumbase/fixtures/page_actions.py,sha256=dbp63c-7asYZyd8aOu57Y3dxQQozp_VJsP5h74s1kBA,66552
|
74
74
|
seleniumbase/fixtures/page_utils.py,sha256=5m7iXpikLs80TJoRO6_gEfXE1AKeQgcH1aFbR8o1C9A,12034
|
75
|
-
seleniumbase/fixtures/shared_utils.py,sha256=
|
75
|
+
seleniumbase/fixtures/shared_utils.py,sha256=G6CsE-Adt-GfuZF-71jXWKSIQW7YZPx8FIM24pVd_yI,8368
|
76
76
|
seleniumbase/fixtures/unittest_helper.py,sha256=sfZ92rZeBAn_sF_yQ3I6_I7h3lyU5-cV_UMegBNoEm8,1294
|
77
77
|
seleniumbase/fixtures/words.py,sha256=FOA4mAYvl3EPVpBTvgvK6YwCL8BdlRCmed685kEe7Vg,7827
|
78
78
|
seleniumbase/fixtures/xpath_to_css.py,sha256=lML56k656fElXJ4NJF07r35FjctrbgQkXUotNk7A-as,8876
|
@@ -88,7 +88,7 @@ seleniumbase/plugins/basic_test_info.py,sha256=8ov6n417gPbqqvrlT4zrch7l2XcRt-GF2
|
|
88
88
|
seleniumbase/plugins/db_reporting_plugin.py,sha256=En09qUCoojrk9-vbcnsoHdSELoGmag2GDIyu3jTiJas,7331
|
89
89
|
seleniumbase/plugins/driver_manager.py,sha256=s20s0pJYaNrG0WNwyIC04oUMRVFjtm6V_nS1-EvFm7g,34492
|
90
90
|
seleniumbase/plugins/page_source.py,sha256=loTnXxOj4kxEukuTZEiGyvKBhY3KDVDMnNlHHheTBDE,1889
|
91
|
-
seleniumbase/plugins/pytest_plugin.py,sha256=
|
91
|
+
seleniumbase/plugins/pytest_plugin.py,sha256=JjpglUqHkfl6rzdg1SkJ7PMtNRpceOgLNbUi2DyKpJI,105416
|
92
92
|
seleniumbase/plugins/s3_logging_plugin.py,sha256=WDfertQgGOW_SRJpFMaekYD6vBVW9VO62POtXXy2HCM,2319
|
93
93
|
seleniumbase/plugins/sb_manager.py,sha256=qCf6RAkAfziLTGgiJvB3V416RxWoTbRLm9wc-KsB8g8,54419
|
94
94
|
seleniumbase/plugins/screen_shots.py,sha256=1hrXw-hzuZ1BR6Yh7AyWX2ABnvnP73-RCbwdz958gj4,1127
|
@@ -119,7 +119,7 @@ seleniumbase/undetected/cdp_driver/browser.py,sha256=n8GYspU7b0pfBT4AqhqY6IdGVOZ
|
|
119
119
|
seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=YhtD2Tm6PLIy9VKbgk8lHdGniS3mObyX4yAC1aG0TgQ,16733
|
120
120
|
seleniumbase/undetected/cdp_driver/config.py,sha256=Rjvde7V-XJ0ihZdTmOmHEVWSuDWm3SprQ3njg8SN3Go,12087
|
121
121
|
seleniumbase/undetected/cdp_driver/connection.py,sha256=sOTUGjbUqKA2hPvDcRCdqw1VQjVGJs7mbgVvzS7ldtE,23360
|
122
|
-
seleniumbase/undetected/cdp_driver/element.py,sha256=
|
122
|
+
seleniumbase/undetected/cdp_driver/element.py,sha256=610eW609khWp2hFn9gKUx4DDxeJdPZ5jb0Vxe1W-9PY,40426
|
123
123
|
seleniumbase/undetected/cdp_driver/tab.py,sha256=cmSUg9fRnIVYgeqs-t8Tcg1FrSVIrM5IBQmCMzvl4OQ,50678
|
124
124
|
seleniumbase/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
125
125
|
seleniumbase/utilities/selenium_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -135,9 +135,9 @@ seleniumbase/utilities/selenium_grid/start-grid-hub.bat,sha256=Ftq-GrAKRYH2ssDPr
|
|
135
135
|
seleniumbase/utilities/selenium_grid/start-grid-hub.sh,sha256=KADv0RUHONLL2_I443QFK8PryBpDmKn5Gy0s4o0vDSM,106
|
136
136
|
seleniumbase/utilities/selenium_ide/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
137
137
|
seleniumbase/utilities/selenium_ide/convert_ide.py,sha256=pZFnqEJQEKZPyNFjkLD29s2HPQgCrWW9XJWpCPhWOoM,31691
|
138
|
-
seleniumbase-4.33.
|
139
|
-
seleniumbase-4.33.
|
140
|
-
seleniumbase-4.33.
|
141
|
-
seleniumbase-4.33.
|
142
|
-
seleniumbase-4.33.
|
143
|
-
seleniumbase-4.33.
|
138
|
+
seleniumbase-4.33.7.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
|
139
|
+
seleniumbase-4.33.7.dist-info/METADATA,sha256=iP-VXv10VT9xAD7UJPlD8tTJi7J88s6D3GCy1gvec6E,86528
|
140
|
+
seleniumbase-4.33.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
141
|
+
seleniumbase-4.33.7.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
|
142
|
+
seleniumbase-4.33.7.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
|
143
|
+
seleniumbase-4.33.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|