seleniumbase 4.34.7__py3-none-any.whl → 4.36.2__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/__init__.py +2 -0
- seleniumbase/__version__.py +1 -1
- seleniumbase/config/proxy_list.py +2 -2
- seleniumbase/console_scripts/sb_mkdir.py +3 -0
- seleniumbase/core/browser_launcher.py +160 -38
- seleniumbase/core/detect_b_ver.py +12 -13
- seleniumbase/core/proxy_helper.py +7 -5
- seleniumbase/core/sb_cdp.py +335 -93
- seleniumbase/core/sb_driver.py +7 -0
- seleniumbase/extensions/ad_block.zip +0 -0
- seleniumbase/extensions/disable_csp.zip +0 -0
- seleniumbase/fixtures/base_case.py +104 -19
- seleniumbase/fixtures/js_utils.py +33 -9
- seleniumbase/plugins/base_plugin.py +12 -15
- seleniumbase/plugins/driver_manager.py +19 -2
- seleniumbase/plugins/pytest_plugin.py +3 -0
- seleniumbase/plugins/sb_manager.py +18 -1
- seleniumbase/plugins/selenium_plugin.py +1 -0
- seleniumbase/undetected/__init__.py +38 -17
- seleniumbase/undetected/cdp_driver/__init__.py +2 -0
- seleniumbase/undetected/cdp_driver/browser.py +16 -10
- seleniumbase/undetected/cdp_driver/cdp_util.py +143 -8
- seleniumbase/undetected/cdp_driver/config.py +10 -0
- seleniumbase/undetected/cdp_driver/connection.py +1 -1
- seleniumbase/undetected/cdp_driver/tab.py +41 -4
- seleniumbase/undetected/webelement.py +3 -2
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info}/METADATA +30 -28
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info}/RECORD +32 -32
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info}/WHEEL +1 -1
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info/licenses}/LICENSE +0 -0
- {seleniumbase-4.34.7.dist-info → seleniumbase-4.36.2.dist-info}/top_level.txt +0 -0
seleniumbase/core/sb_cdp.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Add CDP methods to extend the driver"""
|
2
|
+
import asyncio
|
2
3
|
import fasteners
|
3
4
|
import os
|
4
5
|
import re
|
@@ -11,6 +12,7 @@ from seleniumbase.fixtures import constants
|
|
11
12
|
from seleniumbase.fixtures import js_utils
|
12
13
|
from seleniumbase.fixtures import page_utils
|
13
14
|
from seleniumbase.fixtures import shared_utils
|
15
|
+
from seleniumbase.undetected.cdp_driver import cdp_util
|
14
16
|
|
15
17
|
|
16
18
|
class CDPMethods():
|
@@ -56,12 +58,16 @@ class CDPMethods():
|
|
56
58
|
element, *args, **kwargs
|
57
59
|
)
|
58
60
|
element.focus = lambda: self.__focus(element)
|
61
|
+
element.gui_click = (
|
62
|
+
lambda *args, **kwargs: self.__gui_click(element, *args, **kwargs)
|
63
|
+
)
|
59
64
|
element.highlight_overlay = lambda: self.__highlight_overlay(element)
|
60
65
|
element.mouse_click = lambda: self.__mouse_click(element)
|
61
66
|
element.mouse_drag = (
|
62
67
|
lambda destination: self.__mouse_drag(element, destination)
|
63
68
|
)
|
64
69
|
element.mouse_move = lambda: self.__mouse_move(element)
|
70
|
+
element.press_keys = lambda text: self.__press_keys(element, text)
|
65
71
|
element.query_selector = (
|
66
72
|
lambda selector: self.__query_selector(element, selector)
|
67
73
|
)
|
@@ -91,6 +97,8 @@ class CDPMethods():
|
|
91
97
|
element.get_attribute = (
|
92
98
|
lambda attribute: self.__get_attribute(element, attribute)
|
93
99
|
)
|
100
|
+
# element.get_parent() should come last
|
101
|
+
element.get_parent = lambda: self.__get_parent(element)
|
94
102
|
return element
|
95
103
|
|
96
104
|
def get(self, url):
|
@@ -98,7 +106,7 @@ class CDPMethods():
|
|
98
106
|
driver = self.driver
|
99
107
|
if hasattr(driver, "cdp_base"):
|
100
108
|
driver = driver.cdp_base
|
101
|
-
self.
|
109
|
+
self.loop.run_until_complete(self.page.get(url))
|
102
110
|
url_protocol = url.split(":")[0]
|
103
111
|
safe_url = True
|
104
112
|
if url_protocol not in ["about", "data", "chrome"]:
|
@@ -202,14 +210,17 @@ class CDPMethods():
|
|
202
210
|
element = self.__add_sync_methods(element)
|
203
211
|
return self.__add_sync_methods(element)
|
204
212
|
elif (
|
205
|
-
element
|
213
|
+
element
|
214
|
+
and element.parent
|
206
215
|
and tag_name in element.parent.tag_name.lower()
|
207
216
|
and text.strip() in element.parent.text
|
208
217
|
):
|
209
218
|
element = self.__add_sync_methods(element.parent)
|
210
219
|
return self.__add_sync_methods(element)
|
211
220
|
elif (
|
212
|
-
element
|
221
|
+
element
|
222
|
+
and element.parent
|
223
|
+
and element.parent.parent
|
213
224
|
and tag_name in element.parent.parent.tag_name.lower()
|
214
225
|
and text.strip() in element.parent.parent.text
|
215
226
|
):
|
@@ -262,7 +273,8 @@ class CDPMethods():
|
|
262
273
|
if element not in updated_elements:
|
263
274
|
updated_elements.append(element)
|
264
275
|
elif (
|
265
|
-
element
|
276
|
+
element
|
277
|
+
and element.parent
|
266
278
|
and tag_name in element.parent.tag_name.lower()
|
267
279
|
and text.strip() in element.parent.text
|
268
280
|
):
|
@@ -270,7 +282,9 @@ class CDPMethods():
|
|
270
282
|
if element not in updated_elements:
|
271
283
|
updated_elements.append(element)
|
272
284
|
elif (
|
273
|
-
element
|
285
|
+
element
|
286
|
+
and element.parent
|
287
|
+
and element.parent.parent
|
274
288
|
and tag_name in element.parent.parent.tag_name.lower()
|
275
289
|
and text.strip() in element.parent.parent.text
|
276
290
|
):
|
@@ -280,7 +294,7 @@ class CDPMethods():
|
|
280
294
|
return updated_elements
|
281
295
|
|
282
296
|
def select(self, selector, timeout=None):
|
283
|
-
"""Similar to find_element()
|
297
|
+
"""Similar to find_element()."""
|
284
298
|
if not timeout:
|
285
299
|
timeout = settings.SMALL_TIMEOUT
|
286
300
|
self.__add_light_pause()
|
@@ -289,12 +303,25 @@ class CDPMethods():
|
|
289
303
|
tag_name = selector.split(":contains(")[0].split(" ")[-1]
|
290
304
|
text = selector.split(":contains(")[1].split(")")[0][1:-1]
|
291
305
|
with suppress(Exception):
|
306
|
+
new_timeout = timeout
|
307
|
+
if new_timeout < 1:
|
308
|
+
new_timeout = 1
|
309
|
+
self.loop.run_until_complete(
|
310
|
+
self.page.select(tag_name, timeout=new_timeout)
|
311
|
+
)
|
292
312
|
self.loop.run_until_complete(
|
293
|
-
self.page.
|
313
|
+
self.page.find(text, timeout=new_timeout)
|
294
314
|
)
|
295
|
-
|
296
|
-
|
297
|
-
|
315
|
+
elements = self.find_elements_by_text(text, tag_name=tag_name)
|
316
|
+
if not elements:
|
317
|
+
plural = "s"
|
318
|
+
if timeout == 1:
|
319
|
+
plural = ""
|
320
|
+
msg = "\n Element {%s} was not found after %s second%s!"
|
321
|
+
message = msg % (selector, timeout, plural)
|
322
|
+
raise Exception(message)
|
323
|
+
element = self.__add_sync_methods(elements[0])
|
324
|
+
return element
|
298
325
|
failure = False
|
299
326
|
try:
|
300
327
|
element = self.loop.run_until_complete(
|
@@ -305,11 +332,8 @@ class CDPMethods():
|
|
305
332
|
plural = "s"
|
306
333
|
if timeout == 1:
|
307
334
|
plural = ""
|
308
|
-
|
309
|
-
|
310
|
-
timeout,
|
311
|
-
plural,
|
312
|
-
)
|
335
|
+
msg = "\n Element {%s} was not found after %s second%s!"
|
336
|
+
message = msg % (selector, timeout, plural)
|
313
337
|
if failure:
|
314
338
|
raise Exception(message)
|
315
339
|
element = self.__add_sync_methods(element)
|
@@ -421,6 +445,39 @@ class CDPMethods():
|
|
421
445
|
self.loop.run_until_complete(element.focus_async())
|
422
446
|
)
|
423
447
|
|
448
|
+
def __gui_click(self, element, timeframe=None):
|
449
|
+
element.scroll_into_view()
|
450
|
+
self.__add_light_pause()
|
451
|
+
position = element.get_position()
|
452
|
+
x = position.x
|
453
|
+
y = position.y
|
454
|
+
e_width = position.width
|
455
|
+
e_height = position.height
|
456
|
+
# Relative to window
|
457
|
+
element_rect = {"height": e_height, "width": e_width, "x": x, "y": y}
|
458
|
+
window_rect = self.get_window_rect()
|
459
|
+
w_bottom_y = window_rect["y"] + window_rect["height"]
|
460
|
+
viewport_height = window_rect["innerHeight"]
|
461
|
+
x = window_rect["x"] + element_rect["x"]
|
462
|
+
y = w_bottom_y - viewport_height + element_rect["y"]
|
463
|
+
y_scroll_offset = window_rect["pageYOffset"]
|
464
|
+
y = y - y_scroll_offset
|
465
|
+
x = x + window_rect["scrollX"]
|
466
|
+
y = y + window_rect["scrollY"]
|
467
|
+
# Relative to screen
|
468
|
+
element_rect = {"height": e_height, "width": e_width, "x": x, "y": y}
|
469
|
+
e_width = element_rect["width"]
|
470
|
+
e_height = element_rect["height"]
|
471
|
+
e_x = element_rect["x"]
|
472
|
+
e_y = element_rect["y"]
|
473
|
+
x, y = ((e_x + e_width / 2.0) + 0.5), ((e_y + e_height / 2.0) + 0.5)
|
474
|
+
if not timeframe or not isinstance(timeframe, (int, float)):
|
475
|
+
timeframe = 0.25
|
476
|
+
if timeframe > 3:
|
477
|
+
timeframe = 3
|
478
|
+
self.gui_click_x_y(x, y, timeframe=timeframe)
|
479
|
+
return self.loop.run_until_complete(self.page.wait())
|
480
|
+
|
424
481
|
def __highlight_overlay(self, element):
|
425
482
|
return (
|
426
483
|
self.loop.run_until_complete(element.highlight_overlay_async())
|
@@ -443,6 +500,21 @@ class CDPMethods():
|
|
443
500
|
self.loop.run_until_complete(element.mouse_move_async())
|
444
501
|
)
|
445
502
|
|
503
|
+
def __press_keys(self, element, text):
|
504
|
+
element.scroll_into_view()
|
505
|
+
submit = False
|
506
|
+
if text.endswith("\n") or text.endswith("\r"):
|
507
|
+
submit = True
|
508
|
+
text = text[:-1]
|
509
|
+
for key in text:
|
510
|
+
element.send_keys(key)
|
511
|
+
time.sleep(0.044)
|
512
|
+
if submit:
|
513
|
+
element.send_keys("\r\n")
|
514
|
+
time.sleep(0.044)
|
515
|
+
self.__slow_mode_pause_if_set()
|
516
|
+
return self.loop.run_until_complete(self.page.sleep(0.025))
|
517
|
+
|
446
518
|
def __query_selector(self, element, selector):
|
447
519
|
selector = self.__convert_to_css_if_xpath(selector)
|
448
520
|
element2 = self.loop.run_until_complete(
|
@@ -549,6 +621,9 @@ class CDPMethods():
|
|
549
621
|
pass
|
550
622
|
return None
|
551
623
|
|
624
|
+
def __get_parent(self, element):
|
625
|
+
return self.__add_sync_methods(element.parent)
|
626
|
+
|
552
627
|
def __get_x_scroll_offset(self):
|
553
628
|
x_scroll_offset = self.loop.run_until_complete(
|
554
629
|
self.page.evaluate("window.pageXOffset")
|
@@ -769,6 +844,11 @@ class CDPMethods():
|
|
769
844
|
def highlight_overlay(self, selector):
|
770
845
|
self.find_element(selector).highlight_overlay()
|
771
846
|
|
847
|
+
def get_parent(self, element):
|
848
|
+
if isinstance(element, str):
|
849
|
+
element = self.select(element)
|
850
|
+
return self.__add_sync_methods(element.parent)
|
851
|
+
|
772
852
|
def remove_element(self, selector):
|
773
853
|
self.select(selector).remove_from_dom()
|
774
854
|
|
@@ -800,7 +880,7 @@ class CDPMethods():
|
|
800
880
|
text = text[:-1] + "\r\n"
|
801
881
|
element.send_keys(text)
|
802
882
|
self.__slow_mode_pause_if_set()
|
803
|
-
self.loop.run_until_complete(self.page.
|
883
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
804
884
|
|
805
885
|
def press_keys(self, selector, text, timeout=None):
|
806
886
|
"""Similar to send_keys(), but presses keys at human speed."""
|
@@ -820,7 +900,7 @@ class CDPMethods():
|
|
820
900
|
element.send_keys("\r\n")
|
821
901
|
time.sleep(0.044)
|
822
902
|
self.__slow_mode_pause_if_set()
|
823
|
-
self.loop.run_until_complete(self.page.
|
903
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
824
904
|
|
825
905
|
def type(self, selector, text, timeout=None):
|
826
906
|
"""Similar to send_keys(), but clears the text field first."""
|
@@ -835,7 +915,7 @@ class CDPMethods():
|
|
835
915
|
text = text[:-1] + "\r\n"
|
836
916
|
element.send_keys(text)
|
837
917
|
self.__slow_mode_pause_if_set()
|
838
|
-
self.loop.run_until_complete(self.page.
|
918
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
839
919
|
|
840
920
|
def set_value(self, selector, text, timeout=None):
|
841
921
|
"""Similar to send_keys(), but clears the text field first."""
|
@@ -873,12 +953,31 @@ class CDPMethods():
|
|
873
953
|
self.__add_light_pause()
|
874
954
|
self.send_keys(selector, "\n")
|
875
955
|
self.__slow_mode_pause_if_set()
|
876
|
-
self.loop.run_until_complete(self.page.
|
956
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
957
|
+
|
958
|
+
def submit(self, selector):
|
959
|
+
submit_script = (
|
960
|
+
"""elm = document.querySelector('%s');
|
961
|
+
const event = new KeyboardEvent("keydown", {
|
962
|
+
key: "Enter",
|
963
|
+
keyCode: 13,
|
964
|
+
code: "Enter",
|
965
|
+
which: 13,
|
966
|
+
bubbles: true
|
967
|
+
});
|
968
|
+
elm.dispatchEvent(event);""" % selector
|
969
|
+
)
|
970
|
+
self.loop.run_until_complete(self.page.evaluate(submit_script))
|
877
971
|
|
878
972
|
def evaluate(self, expression):
|
879
973
|
"""Run a JavaScript expression and return the result."""
|
880
|
-
|
881
|
-
|
974
|
+
expression = expression.strip()
|
975
|
+
exp_list = expression.split("\n")
|
976
|
+
if exp_list and exp_list[-1].strip().startswith("return "):
|
977
|
+
expression = (
|
978
|
+
"\n".join(exp_list[0:-1]) + "\n"
|
979
|
+
+ exp_list[-1].strip()[len("return "):]
|
980
|
+
).strip()
|
882
981
|
return self.loop.run_until_complete(
|
883
982
|
self.page.evaluate(expression)
|
884
983
|
)
|
@@ -929,10 +1028,61 @@ class CDPMethods():
|
|
929
1028
|
self.set_window_rect(x, y, width, height)
|
930
1029
|
self.__add_light_pause()
|
931
1030
|
|
1031
|
+
def open_new_window(self, url=None, switch_to=True):
|
1032
|
+
return self.open_new_tab(url=url, switch_to=switch_to)
|
1033
|
+
|
1034
|
+
def switch_to_window(self, window):
|
1035
|
+
self.switch_to_tab(window)
|
1036
|
+
|
1037
|
+
def switch_to_newest_window(self):
|
1038
|
+
self.switch_to_tab(-1)
|
1039
|
+
|
1040
|
+
def open_new_tab(self, url=None, switch_to=True):
|
1041
|
+
if not isinstance(url, str):
|
1042
|
+
url = "about:blank"
|
1043
|
+
self.loop.run_until_complete(self.page.get(url, new_tab=True))
|
1044
|
+
if switch_to:
|
1045
|
+
self.switch_to_newest_tab()
|
1046
|
+
|
1047
|
+
def switch_to_tab(self, tab):
|
1048
|
+
driver = self.driver
|
1049
|
+
if hasattr(driver, "cdp_base"):
|
1050
|
+
driver = driver.cdp_base
|
1051
|
+
if isinstance(tab, int):
|
1052
|
+
self.page = driver.tabs[tab]
|
1053
|
+
elif isinstance(tab, cdp_util.Tab):
|
1054
|
+
self.page = tab
|
1055
|
+
else:
|
1056
|
+
raise Exception("`tab` must be an int or a Tab type!")
|
1057
|
+
self.bring_active_window_to_front()
|
1058
|
+
|
1059
|
+
def switch_to_newest_tab(self):
|
1060
|
+
self.switch_to_tab(-1)
|
1061
|
+
|
1062
|
+
def close_active_tab(self):
|
1063
|
+
"""Close the active tab.
|
1064
|
+
The active tab is the one currenly controlled by CDP.
|
1065
|
+
The active tab MIGHT NOT be the currently visible tab!
|
1066
|
+
(If a page opens a new tab, the new tab WON'T be active)
|
1067
|
+
To switch the active tab, call: sb.switch_to_tab(tab)"""
|
1068
|
+
return self.loop.run_until_complete(self.page.close())
|
1069
|
+
|
1070
|
+
def get_active_tab(self):
|
1071
|
+
"""Return the active tab.
|
1072
|
+
The active tab is the one currenly controlled by CDP.
|
1073
|
+
The active tab MIGHT NOT be the currently visible tab!
|
1074
|
+
(If a page opens a new tab, the new tab WON'T be active)
|
1075
|
+
To switch the active tab, call: sb.switch_to_tab(tab)"""
|
1076
|
+
return self.page
|
1077
|
+
|
1078
|
+
def get_tabs(self):
|
1079
|
+
driver = self.driver
|
1080
|
+
if hasattr(driver, "cdp_base"):
|
1081
|
+
driver = driver.cdp_base
|
1082
|
+
return driver.tabs
|
1083
|
+
|
932
1084
|
def get_window(self):
|
933
|
-
return self.loop.run_until_complete(
|
934
|
-
self.page.get_window()
|
935
|
-
)
|
1085
|
+
return self.loop.run_until_complete(self.page.get_window())
|
936
1086
|
|
937
1087
|
def get_text(self, selector):
|
938
1088
|
return self.find_element(selector).text_all
|
@@ -979,6 +1129,16 @@ class CDPMethods():
|
|
979
1129
|
self.page.evaluate("navigator.language || navigator.languages[0]")
|
980
1130
|
)
|
981
1131
|
|
1132
|
+
def get_local_storage_item(self, key):
|
1133
|
+
js_code = """localStorage.getItem('%s');""" % key
|
1134
|
+
with suppress(Exception):
|
1135
|
+
return self.loop.run_until_complete(self.page.evaluate(js_code))
|
1136
|
+
|
1137
|
+
def get_session_storage_item(self, key):
|
1138
|
+
js_code = """sessionStorage.getItem('%s');""" % key
|
1139
|
+
with suppress(Exception):
|
1140
|
+
return self.loop.run_until_complete(self.page.evaluate(js_code))
|
1141
|
+
|
982
1142
|
def get_screen_rect(self):
|
983
1143
|
coordinates = self.loop.run_until_complete(
|
984
1144
|
self.page.js_dumps("window.screen")
|
@@ -1126,14 +1286,10 @@ class CDPMethods():
|
|
1126
1286
|
return ((e_x + e_width / 2.0) + 0.5, (e_y + e_height / 2.0) + 0.5)
|
1127
1287
|
|
1128
1288
|
def get_document(self):
|
1129
|
-
return self.loop.run_until_complete(
|
1130
|
-
self.page.get_document()
|
1131
|
-
)
|
1289
|
+
return self.loop.run_until_complete(self.page.get_document())
|
1132
1290
|
|
1133
1291
|
def get_flattened_document(self):
|
1134
|
-
return self.loop.run_until_complete(
|
1135
|
-
self.page.get_flattened_document()
|
1136
|
-
)
|
1292
|
+
return self.loop.run_until_complete(self.page.get_flattened_document())
|
1137
1293
|
|
1138
1294
|
def get_element_attributes(self, selector):
|
1139
1295
|
selector = self.__convert_to_css_if_xpath(selector)
|
@@ -1170,6 +1326,16 @@ class CDPMethods():
|
|
1170
1326
|
"""(Settings will take effect on the next page load)"""
|
1171
1327
|
self.loop.run_until_complete(self.page.set_locale(locale))
|
1172
1328
|
|
1329
|
+
def set_local_storage_item(self, key, value):
|
1330
|
+
js_code = """localStorage.setItem('%s','%s');""" % (key, value)
|
1331
|
+
with suppress(Exception):
|
1332
|
+
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1333
|
+
|
1334
|
+
def set_session_storage_item(self, key, value):
|
1335
|
+
js_code = """sessionStorage.setItem('%s','%s');""" % (key, value)
|
1336
|
+
with suppress(Exception):
|
1337
|
+
self.loop.run_until_complete(self.page.evaluate(js_code))
|
1338
|
+
|
1173
1339
|
def set_attributes(self, selector, attribute, value):
|
1174
1340
|
"""This method uses JavaScript to set/update a common attribute.
|
1175
1341
|
All matching selectors from querySelectorAll() are used.
|
@@ -1308,7 +1474,7 @@ class CDPMethods():
|
|
1308
1474
|
pyautogui.press(key)
|
1309
1475
|
time.sleep(0.044)
|
1310
1476
|
self.__slow_mode_pause_if_set()
|
1311
|
-
self.loop.run_until_complete(self.page.
|
1477
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1312
1478
|
|
1313
1479
|
def gui_press_keys(self, keys):
|
1314
1480
|
self.__install_pyautogui_if_missing()
|
@@ -1323,7 +1489,7 @@ class CDPMethods():
|
|
1323
1489
|
pyautogui.press(key)
|
1324
1490
|
time.sleep(0.044)
|
1325
1491
|
self.__slow_mode_pause_if_set()
|
1326
|
-
self.loop.run_until_complete(self.page.
|
1492
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1327
1493
|
|
1328
1494
|
def gui_write(self, text):
|
1329
1495
|
self.__install_pyautogui_if_missing()
|
@@ -1336,7 +1502,7 @@ class CDPMethods():
|
|
1336
1502
|
self.__make_sure_pyautogui_lock_is_writable()
|
1337
1503
|
pyautogui.write(text)
|
1338
1504
|
self.__slow_mode_pause_if_set()
|
1339
|
-
self.loop.run_until_complete(self.page.
|
1505
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1340
1506
|
|
1341
1507
|
def __gui_click_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
1342
1508
|
self.__install_pyautogui_if_missing()
|
@@ -1666,59 +1832,93 @@ class CDPMethods():
|
|
1666
1832
|
return True
|
1667
1833
|
return False
|
1668
1834
|
|
1669
|
-
def
|
1670
|
-
|
1671
|
-
|
1835
|
+
def is_text_visible(self, text, selector="body"):
|
1836
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1837
|
+
text = text.strip()
|
1838
|
+
element = None
|
1672
1839
|
try:
|
1673
|
-
self.
|
1840
|
+
element = self.find_element(selector, timeout=0.1)
|
1674
1841
|
except Exception:
|
1675
|
-
|
1676
|
-
|
1677
|
-
if
|
1678
|
-
return
|
1679
|
-
|
1680
|
-
raise Exception("Element {%s} was not visible!" % selector)
|
1842
|
+
return False
|
1843
|
+
with suppress(Exception):
|
1844
|
+
if text in element.text_all:
|
1845
|
+
return True
|
1846
|
+
return False
|
1681
1847
|
|
1682
|
-
def
|
1683
|
-
|
1848
|
+
def is_exact_text_visible(self, text, selector="body"):
|
1849
|
+
selector = self.__convert_to_css_if_xpath(selector)
|
1850
|
+
text = text.strip()
|
1851
|
+
element = None
|
1852
|
+
try:
|
1853
|
+
element = self.find_element(selector, timeout=0.1)
|
1854
|
+
except Exception:
|
1855
|
+
return False
|
1856
|
+
with suppress(Exception):
|
1857
|
+
if text == element.text_all.strip():
|
1858
|
+
return True
|
1859
|
+
return False
|
1860
|
+
|
1861
|
+
def wait_for_text(self, text, selector="body", timeout=None):
|
1684
1862
|
if not timeout:
|
1685
1863
|
timeout = settings.SMALL_TIMEOUT
|
1864
|
+
start_ms = time.time() * 1000.0
|
1865
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1866
|
+
text = text.strip()
|
1867
|
+
element = None
|
1686
1868
|
try:
|
1687
|
-
self.
|
1869
|
+
element = self.find_element(selector, timeout=timeout)
|
1688
1870
|
except Exception:
|
1689
|
-
raise Exception("Element {%s}
|
1690
|
-
for i in range(
|
1691
|
-
|
1871
|
+
raise Exception("Element {%s} not found!" % selector)
|
1872
|
+
for i in range(int(timeout * 10)):
|
1873
|
+
with suppress(Exception):
|
1874
|
+
element = self.find_element(selector, timeout=0.1)
|
1875
|
+
if text in element.text_all:
|
1692
1876
|
return True
|
1877
|
+
now_ms = time.time() * 1000.0
|
1878
|
+
if now_ms >= stop_ms:
|
1879
|
+
break
|
1693
1880
|
time.sleep(0.1)
|
1694
|
-
raise Exception(
|
1881
|
+
raise Exception(
|
1882
|
+
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1883
|
+
% (text, selector, element.text_all)
|
1884
|
+
)
|
1695
1885
|
|
1696
|
-
def
|
1697
|
-
"""Same as assert_element()"""
|
1886
|
+
def wait_for_text_not_visible(self, text, selector="body", timeout=None):
|
1698
1887
|
if not timeout:
|
1699
1888
|
timeout = settings.SMALL_TIMEOUT
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
if self.is_element_visible(selector):
|
1889
|
+
text = text.strip()
|
1890
|
+
start_ms = time.time() * 1000.0
|
1891
|
+
stop_ms = start_ms + (timeout * 1000.0)
|
1892
|
+
for i in range(int(timeout * 10)):
|
1893
|
+
if not self.is_text_visible(text, selector):
|
1706
1894
|
return True
|
1895
|
+
now_ms = time.time() * 1000.0
|
1896
|
+
if now_ms >= stop_ms:
|
1897
|
+
break
|
1707
1898
|
time.sleep(0.1)
|
1708
|
-
|
1899
|
+
plural = "s"
|
1900
|
+
if timeout == 1:
|
1901
|
+
plural = ""
|
1902
|
+
raise Exception(
|
1903
|
+
"Text {%s} in {%s} was still visible after %s second%s!"
|
1904
|
+
% (text, selector, timeout, plural)
|
1905
|
+
)
|
1709
1906
|
|
1710
|
-
def
|
1711
|
-
"""Assert element is present in the DOM. (Visibility NOT required)"""
|
1907
|
+
def wait_for_element_visible(self, selector, timeout=None):
|
1712
1908
|
if not timeout:
|
1713
1909
|
timeout = settings.SMALL_TIMEOUT
|
1714
1910
|
try:
|
1715
1911
|
self.select(selector, timeout=timeout)
|
1716
1912
|
except Exception:
|
1717
1913
|
raise Exception("Element {%s} was not found!" % selector)
|
1718
|
-
|
1914
|
+
for i in range(30):
|
1915
|
+
if self.is_element_visible(selector):
|
1916
|
+
return self.select(selector)
|
1917
|
+
time.sleep(0.1)
|
1918
|
+
raise Exception("Element {%s} was not visible!" % selector)
|
1719
1919
|
|
1720
|
-
def
|
1721
|
-
"""
|
1920
|
+
def wait_for_element_not_visible(self, selector, timeout=None):
|
1921
|
+
"""Wait for element to not be visible on page. (May still be in DOM)"""
|
1722
1922
|
if not timeout:
|
1723
1923
|
timeout = settings.SMALL_TIMEOUT
|
1724
1924
|
start_ms = time.time() * 1000.0
|
@@ -1726,6 +1926,8 @@ class CDPMethods():
|
|
1726
1926
|
for i in range(int(timeout * 10)):
|
1727
1927
|
if not self.is_element_present(selector):
|
1728
1928
|
return True
|
1929
|
+
elif not self.is_element_visible(selector):
|
1930
|
+
return True
|
1729
1931
|
now_ms = time.time() * 1000.0
|
1730
1932
|
if now_ms >= stop_ms:
|
1731
1933
|
break
|
@@ -1734,12 +1936,12 @@ class CDPMethods():
|
|
1734
1936
|
if timeout == 1:
|
1735
1937
|
plural = ""
|
1736
1938
|
raise Exception(
|
1737
|
-
"Element {%s} was still
|
1939
|
+
"Element {%s} was still visible after %s second%s!"
|
1738
1940
|
% (selector, timeout, plural)
|
1739
1941
|
)
|
1740
1942
|
|
1741
|
-
def
|
1742
|
-
"""
|
1943
|
+
def wait_for_element_absent(self, selector, timeout=None):
|
1944
|
+
"""Wait for element to not be present in the DOM."""
|
1743
1945
|
if not timeout:
|
1744
1946
|
timeout = settings.SMALL_TIMEOUT
|
1745
1947
|
start_ms = time.time() * 1000.0
|
@@ -1747,8 +1949,6 @@ class CDPMethods():
|
|
1747
1949
|
for i in range(int(timeout * 10)):
|
1748
1950
|
if not self.is_element_present(selector):
|
1749
1951
|
return True
|
1750
|
-
elif not self.is_element_visible(selector):
|
1751
|
-
return True
|
1752
1952
|
now_ms = time.time() * 1000.0
|
1753
1953
|
if now_ms >= stop_ms:
|
1754
1954
|
break
|
@@ -1757,10 +1957,49 @@ class CDPMethods():
|
|
1757
1957
|
if timeout == 1:
|
1758
1958
|
plural = ""
|
1759
1959
|
raise Exception(
|
1760
|
-
"Element {%s} was still
|
1960
|
+
"Element {%s} was still present after %s second%s!"
|
1761
1961
|
% (selector, timeout, plural)
|
1762
1962
|
)
|
1763
1963
|
|
1964
|
+
def assert_element(self, selector, timeout=None):
|
1965
|
+
"""Same as assert_element_visible()"""
|
1966
|
+
self.assert_element_visible(selector, timeout=timeout)
|
1967
|
+
return True
|
1968
|
+
|
1969
|
+
def assert_element_visible(self, selector, timeout=None):
|
1970
|
+
"""Same as assert_element()"""
|
1971
|
+
if not timeout:
|
1972
|
+
timeout = settings.SMALL_TIMEOUT
|
1973
|
+
try:
|
1974
|
+
self.select(selector, timeout=timeout)
|
1975
|
+
except Exception:
|
1976
|
+
raise Exception("Element {%s} was not found!" % selector)
|
1977
|
+
for i in range(30):
|
1978
|
+
if self.is_element_visible(selector):
|
1979
|
+
return True
|
1980
|
+
time.sleep(0.1)
|
1981
|
+
raise Exception("Element {%s} was not visible!" % selector)
|
1982
|
+
|
1983
|
+
def assert_element_present(self, selector, timeout=None):
|
1984
|
+
"""Assert element is present in the DOM. (Visibility NOT required)"""
|
1985
|
+
if not timeout:
|
1986
|
+
timeout = settings.SMALL_TIMEOUT
|
1987
|
+
try:
|
1988
|
+
self.select(selector, timeout=timeout)
|
1989
|
+
except Exception:
|
1990
|
+
raise Exception("Element {%s} was not found!" % selector)
|
1991
|
+
return True
|
1992
|
+
|
1993
|
+
def assert_element_absent(self, selector, timeout=None):
|
1994
|
+
"""Assert element is not present in the DOM."""
|
1995
|
+
self.wait_for_element_absent(selector, timeout=timeout)
|
1996
|
+
return True
|
1997
|
+
|
1998
|
+
def assert_element_not_visible(self, selector, timeout=None):
|
1999
|
+
"""Assert element is not visible on page. (May still be in DOM)"""
|
2000
|
+
self.wait_for_element_not_visible(selector, timeout=timeout)
|
2001
|
+
return True
|
2002
|
+
|
1764
2003
|
def assert_element_attribute(self, selector, attribute, value=None):
|
1765
2004
|
attributes = self.get_element_attributes(selector)
|
1766
2005
|
if attribute not in attributes:
|
@@ -1837,29 +2076,9 @@ class CDPMethods():
|
|
1837
2076
|
raise Exception(error % (expected, actual))
|
1838
2077
|
|
1839
2078
|
def assert_text(self, text, selector="body", timeout=None):
|
1840
|
-
|
1841
|
-
|
1842
|
-
|
1843
|
-
stop_ms = start_ms + (timeout * 1000.0)
|
1844
|
-
text = text.strip()
|
1845
|
-
element = None
|
1846
|
-
try:
|
1847
|
-
element = self.find_element(selector, timeout=timeout)
|
1848
|
-
except Exception:
|
1849
|
-
raise Exception("Element {%s} not found!" % selector)
|
1850
|
-
for i in range(int(timeout * 10)):
|
1851
|
-
with suppress(Exception):
|
1852
|
-
element = self.find_element(selector, timeout=0.1)
|
1853
|
-
if text in element.text_all:
|
1854
|
-
return True
|
1855
|
-
now_ms = time.time() * 1000.0
|
1856
|
-
if now_ms >= stop_ms:
|
1857
|
-
break
|
1858
|
-
time.sleep(0.1)
|
1859
|
-
raise Exception(
|
1860
|
-
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1861
|
-
% (text, selector, element.text_all)
|
1862
|
-
)
|
2079
|
+
"""Same as wait_for_text()"""
|
2080
|
+
self.wait_for_text(text, selector=selector, timeout=timeout)
|
2081
|
+
return True
|
1863
2082
|
|
1864
2083
|
def assert_exact_text(self, text, selector="body", timeout=None):
|
1865
2084
|
if not timeout:
|
@@ -1889,6 +2108,13 @@ class CDPMethods():
|
|
1889
2108
|
% (text, element.text_all, selector)
|
1890
2109
|
)
|
1891
2110
|
|
2111
|
+
def assert_text_not_visible(self, text, selector="body", timeout=None):
|
2112
|
+
"""Raises an exception if the text is still visible after timeout."""
|
2113
|
+
self.wait_for_text_not_visible(
|
2114
|
+
text, selector=selector, timeout=timeout
|
2115
|
+
)
|
2116
|
+
return True
|
2117
|
+
|
1892
2118
|
def assert_true(self, expression):
|
1893
2119
|
if not expression:
|
1894
2120
|
raise AssertionError("%s is not true" % expression)
|
@@ -1954,3 +2180,19 @@ class CDPMethods():
|
|
1954
2180
|
)
|
1955
2181
|
else:
|
1956
2182
|
self.select(selector).save_screenshot(filename)
|
2183
|
+
|
2184
|
+
def print_to_pdf(self, name, folder=None):
|
2185
|
+
filename = name
|
2186
|
+
if folder:
|
2187
|
+
filename = os.path.join(folder, name)
|
2188
|
+
self.loop.run_until_complete(self.page.print_to_pdf(filename))
|
2189
|
+
|
2190
|
+
|
2191
|
+
class Chrome(CDPMethods):
|
2192
|
+
def __init__(self, url=None, **kwargs):
|
2193
|
+
if not url:
|
2194
|
+
url = "about:blank"
|
2195
|
+
loop = asyncio.new_event_loop()
|
2196
|
+
driver = cdp_util.start_sync(**kwargs)
|
2197
|
+
page = loop.run_until_complete(driver.get(url))
|
2198
|
+
super().__init__(loop, page, driver)
|