seleniumbase 4.34.8__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 +328 -91
- 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 +135 -11
- seleniumbase/undetected/cdp_driver/config.py +10 -0
- seleniumbase/undetected/cdp_driver/connection.py +1 -1
- seleniumbase/undetected/cdp_driver/tab.py +37 -4
- seleniumbase/undetected/webelement.py +3 -2
- {seleniumbase-4.34.8.dist-info → seleniumbase-4.36.2.dist-info}/METADATA +30 -28
- {seleniumbase-4.34.8.dist-info → seleniumbase-4.36.2.dist-info}/RECORD +32 -32
- {seleniumbase-4.34.8.dist-info → seleniumbase-4.36.2.dist-info}/WHEEL +1 -1
- {seleniumbase-4.34.8.dist-info → seleniumbase-4.36.2.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.34.8.dist-info → seleniumbase-4.36.2.dist-info/licenses}/LICENSE +0 -0
- {seleniumbase-4.34.8.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,7 +953,21 @@ 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."""
|
@@ -934,10 +1028,61 @@ class CDPMethods():
|
|
934
1028
|
self.set_window_rect(x, y, width, height)
|
935
1029
|
self.__add_light_pause()
|
936
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
|
+
|
937
1084
|
def get_window(self):
|
938
|
-
return self.loop.run_until_complete(
|
939
|
-
self.page.get_window()
|
940
|
-
)
|
1085
|
+
return self.loop.run_until_complete(self.page.get_window())
|
941
1086
|
|
942
1087
|
def get_text(self, selector):
|
943
1088
|
return self.find_element(selector).text_all
|
@@ -984,6 +1129,16 @@ class CDPMethods():
|
|
984
1129
|
self.page.evaluate("navigator.language || navigator.languages[0]")
|
985
1130
|
)
|
986
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
|
+
|
987
1142
|
def get_screen_rect(self):
|
988
1143
|
coordinates = self.loop.run_until_complete(
|
989
1144
|
self.page.js_dumps("window.screen")
|
@@ -1131,14 +1286,10 @@ class CDPMethods():
|
|
1131
1286
|
return ((e_x + e_width / 2.0) + 0.5, (e_y + e_height / 2.0) + 0.5)
|
1132
1287
|
|
1133
1288
|
def get_document(self):
|
1134
|
-
return self.loop.run_until_complete(
|
1135
|
-
self.page.get_document()
|
1136
|
-
)
|
1289
|
+
return self.loop.run_until_complete(self.page.get_document())
|
1137
1290
|
|
1138
1291
|
def get_flattened_document(self):
|
1139
|
-
return self.loop.run_until_complete(
|
1140
|
-
self.page.get_flattened_document()
|
1141
|
-
)
|
1292
|
+
return self.loop.run_until_complete(self.page.get_flattened_document())
|
1142
1293
|
|
1143
1294
|
def get_element_attributes(self, selector):
|
1144
1295
|
selector = self.__convert_to_css_if_xpath(selector)
|
@@ -1175,6 +1326,16 @@ class CDPMethods():
|
|
1175
1326
|
"""(Settings will take effect on the next page load)"""
|
1176
1327
|
self.loop.run_until_complete(self.page.set_locale(locale))
|
1177
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
|
+
|
1178
1339
|
def set_attributes(self, selector, attribute, value):
|
1179
1340
|
"""This method uses JavaScript to set/update a common attribute.
|
1180
1341
|
All matching selectors from querySelectorAll() are used.
|
@@ -1313,7 +1474,7 @@ class CDPMethods():
|
|
1313
1474
|
pyautogui.press(key)
|
1314
1475
|
time.sleep(0.044)
|
1315
1476
|
self.__slow_mode_pause_if_set()
|
1316
|
-
self.loop.run_until_complete(self.page.
|
1477
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1317
1478
|
|
1318
1479
|
def gui_press_keys(self, keys):
|
1319
1480
|
self.__install_pyautogui_if_missing()
|
@@ -1328,7 +1489,7 @@ class CDPMethods():
|
|
1328
1489
|
pyautogui.press(key)
|
1329
1490
|
time.sleep(0.044)
|
1330
1491
|
self.__slow_mode_pause_if_set()
|
1331
|
-
self.loop.run_until_complete(self.page.
|
1492
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1332
1493
|
|
1333
1494
|
def gui_write(self, text):
|
1334
1495
|
self.__install_pyautogui_if_missing()
|
@@ -1341,7 +1502,7 @@ class CDPMethods():
|
|
1341
1502
|
self.__make_sure_pyautogui_lock_is_writable()
|
1342
1503
|
pyautogui.write(text)
|
1343
1504
|
self.__slow_mode_pause_if_set()
|
1344
|
-
self.loop.run_until_complete(self.page.
|
1505
|
+
self.loop.run_until_complete(self.page.sleep(0.025))
|
1345
1506
|
|
1346
1507
|
def __gui_click_x_y(self, x, y, timeframe=0.25, uc_lock=False):
|
1347
1508
|
self.__install_pyautogui_if_missing()
|
@@ -1671,59 +1832,93 @@ class CDPMethods():
|
|
1671
1832
|
return True
|
1672
1833
|
return False
|
1673
1834
|
|
1674
|
-
def
|
1675
|
-
|
1676
|
-
|
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
|
1677
1839
|
try:
|
1678
|
-
self.
|
1840
|
+
element = self.find_element(selector, timeout=0.1)
|
1679
1841
|
except Exception:
|
1680
|
-
|
1681
|
-
|
1682
|
-
if
|
1683
|
-
return
|
1684
|
-
|
1685
|
-
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
|
1686
1847
|
|
1687
|
-
def
|
1688
|
-
|
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):
|
1689
1862
|
if not timeout:
|
1690
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
|
1691
1868
|
try:
|
1692
|
-
self.
|
1869
|
+
element = self.find_element(selector, timeout=timeout)
|
1693
1870
|
except Exception:
|
1694
|
-
raise Exception("Element {%s}
|
1695
|
-
for i in range(
|
1696
|
-
|
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:
|
1697
1876
|
return True
|
1877
|
+
now_ms = time.time() * 1000.0
|
1878
|
+
if now_ms >= stop_ms:
|
1879
|
+
break
|
1698
1880
|
time.sleep(0.1)
|
1699
|
-
raise Exception(
|
1881
|
+
raise Exception(
|
1882
|
+
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1883
|
+
% (text, selector, element.text_all)
|
1884
|
+
)
|
1700
1885
|
|
1701
|
-
def
|
1702
|
-
"""Same as assert_element()"""
|
1886
|
+
def wait_for_text_not_visible(self, text, selector="body", timeout=None):
|
1703
1887
|
if not timeout:
|
1704
1888
|
timeout = settings.SMALL_TIMEOUT
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
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):
|
1711
1894
|
return True
|
1895
|
+
now_ms = time.time() * 1000.0
|
1896
|
+
if now_ms >= stop_ms:
|
1897
|
+
break
|
1712
1898
|
time.sleep(0.1)
|
1713
|
-
|
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
|
+
)
|
1714
1906
|
|
1715
|
-
def
|
1716
|
-
"""Assert element is present in the DOM. (Visibility NOT required)"""
|
1907
|
+
def wait_for_element_visible(self, selector, timeout=None):
|
1717
1908
|
if not timeout:
|
1718
1909
|
timeout = settings.SMALL_TIMEOUT
|
1719
1910
|
try:
|
1720
1911
|
self.select(selector, timeout=timeout)
|
1721
1912
|
except Exception:
|
1722
1913
|
raise Exception("Element {%s} was not found!" % selector)
|
1723
|
-
|
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)
|
1724
1919
|
|
1725
|
-
def
|
1726
|
-
"""
|
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)"""
|
1727
1922
|
if not timeout:
|
1728
1923
|
timeout = settings.SMALL_TIMEOUT
|
1729
1924
|
start_ms = time.time() * 1000.0
|
@@ -1731,6 +1926,8 @@ class CDPMethods():
|
|
1731
1926
|
for i in range(int(timeout * 10)):
|
1732
1927
|
if not self.is_element_present(selector):
|
1733
1928
|
return True
|
1929
|
+
elif not self.is_element_visible(selector):
|
1930
|
+
return True
|
1734
1931
|
now_ms = time.time() * 1000.0
|
1735
1932
|
if now_ms >= stop_ms:
|
1736
1933
|
break
|
@@ -1739,12 +1936,12 @@ class CDPMethods():
|
|
1739
1936
|
if timeout == 1:
|
1740
1937
|
plural = ""
|
1741
1938
|
raise Exception(
|
1742
|
-
"Element {%s} was still
|
1939
|
+
"Element {%s} was still visible after %s second%s!"
|
1743
1940
|
% (selector, timeout, plural)
|
1744
1941
|
)
|
1745
1942
|
|
1746
|
-
def
|
1747
|
-
"""
|
1943
|
+
def wait_for_element_absent(self, selector, timeout=None):
|
1944
|
+
"""Wait for element to not be present in the DOM."""
|
1748
1945
|
if not timeout:
|
1749
1946
|
timeout = settings.SMALL_TIMEOUT
|
1750
1947
|
start_ms = time.time() * 1000.0
|
@@ -1752,8 +1949,6 @@ class CDPMethods():
|
|
1752
1949
|
for i in range(int(timeout * 10)):
|
1753
1950
|
if not self.is_element_present(selector):
|
1754
1951
|
return True
|
1755
|
-
elif not self.is_element_visible(selector):
|
1756
|
-
return True
|
1757
1952
|
now_ms = time.time() * 1000.0
|
1758
1953
|
if now_ms >= stop_ms:
|
1759
1954
|
break
|
@@ -1762,10 +1957,49 @@ class CDPMethods():
|
|
1762
1957
|
if timeout == 1:
|
1763
1958
|
plural = ""
|
1764
1959
|
raise Exception(
|
1765
|
-
"Element {%s} was still
|
1960
|
+
"Element {%s} was still present after %s second%s!"
|
1766
1961
|
% (selector, timeout, plural)
|
1767
1962
|
)
|
1768
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
|
+
|
1769
2003
|
def assert_element_attribute(self, selector, attribute, value=None):
|
1770
2004
|
attributes = self.get_element_attributes(selector)
|
1771
2005
|
if attribute not in attributes:
|
@@ -1842,29 +2076,9 @@ class CDPMethods():
|
|
1842
2076
|
raise Exception(error % (expected, actual))
|
1843
2077
|
|
1844
2078
|
def assert_text(self, text, selector="body", timeout=None):
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
1848
|
-
stop_ms = start_ms + (timeout * 1000.0)
|
1849
|
-
text = text.strip()
|
1850
|
-
element = None
|
1851
|
-
try:
|
1852
|
-
element = self.find_element(selector, timeout=timeout)
|
1853
|
-
except Exception:
|
1854
|
-
raise Exception("Element {%s} not found!" % selector)
|
1855
|
-
for i in range(int(timeout * 10)):
|
1856
|
-
with suppress(Exception):
|
1857
|
-
element = self.find_element(selector, timeout=0.1)
|
1858
|
-
if text in element.text_all:
|
1859
|
-
return True
|
1860
|
-
now_ms = time.time() * 1000.0
|
1861
|
-
if now_ms >= stop_ms:
|
1862
|
-
break
|
1863
|
-
time.sleep(0.1)
|
1864
|
-
raise Exception(
|
1865
|
-
"Text {%s} not found in {%s}! Actual text: {%s}"
|
1866
|
-
% (text, selector, element.text_all)
|
1867
|
-
)
|
2079
|
+
"""Same as wait_for_text()"""
|
2080
|
+
self.wait_for_text(text, selector=selector, timeout=timeout)
|
2081
|
+
return True
|
1868
2082
|
|
1869
2083
|
def assert_exact_text(self, text, selector="body", timeout=None):
|
1870
2084
|
if not timeout:
|
@@ -1894,6 +2108,13 @@ class CDPMethods():
|
|
1894
2108
|
% (text, element.text_all, selector)
|
1895
2109
|
)
|
1896
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
|
+
|
1897
2118
|
def assert_true(self, expression):
|
1898
2119
|
if not expression:
|
1899
2120
|
raise AssertionError("%s is not true" % expression)
|
@@ -1959,3 +2180,19 @@ class CDPMethods():
|
|
1959
2180
|
)
|
1960
2181
|
else:
|
1961
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)
|