seleniumbase 4.33.5__py3-none-any.whl → 4.33.7__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|