seleniumbase 4.32.9__py3-none-any.whl → 4.32.10__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.
@@ -39,7 +39,9 @@ class CDPMethods():
39
39
  return element
40
40
  element.clear_input = lambda: self.__clear_input(element)
41
41
  element.click = lambda: self.__click(element)
42
- element.flash = lambda: self.__flash(element)
42
+ element.flash = lambda *args, **kwargs: self.__flash(
43
+ element, *args, **kwargs
44
+ )
43
45
  element.focus = lambda: self.__focus(element)
44
46
  element.highlight_overlay = lambda: self.__highlight_overlay(element)
45
47
  element.mouse_click = lambda: self.__mouse_click(element)
@@ -87,6 +89,10 @@ class CDPMethods():
87
89
  safe_url = False
88
90
  if not safe_url:
89
91
  time.sleep(constants.UC.CDP_MODE_OPEN_WAIT)
92
+ if shared_utils.is_windows():
93
+ time.sleep(constants.UC.EXTRA_WINDOWS_WAIT)
94
+ else:
95
+ time.sleep(0.012)
90
96
  self.__slow_mode_pause_if_set()
91
97
  self.loop.run_until_complete(self.page.wait())
92
98
 
@@ -186,7 +192,10 @@ class CDPMethods():
186
192
  )
187
193
  updated_elements = []
188
194
  for element in elements:
189
- if not tag_name or tag_name.lower() == element.tag_name.lower():
195
+ if (
196
+ not tag_name
197
+ or tag_name.lower().strip() in element.tag_name.lower().strip()
198
+ ):
190
199
  element = self.__add_sync_methods(element)
191
200
  updated_elements.append(element)
192
201
  self.__slow_mode_pause_if_set()
@@ -258,9 +267,11 @@ class CDPMethods():
258
267
  self.loop.run_until_complete(self.page.wait())
259
268
  return result
260
269
 
261
- def __flash(self, element):
270
+ def __flash(self, element, *args, **kwargs):
262
271
  return (
263
- self.loop.run_until_complete(element.flash_async())
272
+ self.loop.run_until_complete(
273
+ element.flash_async(*args, **kwargs)
274
+ )
264
275
  )
265
276
 
266
277
  def __focus(self, element):
@@ -292,11 +303,11 @@ class CDPMethods():
292
303
 
293
304
  def __query_selector(self, element, selector):
294
305
  selector = self.__convert_to_css_if_xpath(selector)
295
- element = self.loop.run_until_complete(
306
+ element2 = self.loop.run_until_complete(
296
307
  element.query_selector_async(selector)
297
308
  )
298
- element = self.__add_sync_methods(element)
299
- return element
309
+ element2 = self.__add_sync_methods(element2)
310
+ return element2
300
311
 
301
312
  def __query_selector_all(self, element, selector):
302
313
  selector = self.__convert_to_css_if_xpath(selector)
@@ -431,6 +442,7 @@ class CDPMethods():
431
442
 
432
443
  def bring_active_window_to_front(self):
433
444
  self.loop.run_until_complete(self.page.bring_to_front())
445
+ self.__add_light_pause()
434
446
 
435
447
  def get_active_element(self):
436
448
  return self.loop.run_until_complete(
@@ -467,6 +479,19 @@ class CDPMethods():
467
479
  self.__slow_mode_pause_if_set()
468
480
  self.loop.run_until_complete(self.page.wait())
469
481
 
482
+ def click_visible_elements(self, selector):
483
+ elements = self.select_all(selector)
484
+ for element in elements:
485
+ try:
486
+ position = element.get_position()
487
+ if (position.width != 0 or position.height != 0):
488
+ element.click()
489
+ time.sleep(0.0375)
490
+ self.__slow_mode_pause_if_set()
491
+ self.loop.run_until_complete(self.page.wait())
492
+ except Exception:
493
+ pass
494
+
470
495
  def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT):
471
496
  """(Attempt simulating a mouse click)"""
472
497
  self.__slow_mode_pause_if_set()
@@ -491,9 +516,44 @@ class CDPMethods():
491
516
  element = self.find_element(parent_selector)
492
517
  return element.query_selector(selector)
493
518
 
494
- def flash(self, selector):
519
+ def select_option_by_text(self, dropdown_selector, option):
520
+ element = self.find_element(dropdown_selector)
521
+ options = element.query_selector_all("option")
522
+ for found_option in options:
523
+ if found_option.text.strip() == option.strip():
524
+ found_option.select_option()
525
+ return
526
+ raise Exception(
527
+ "Unable to find text option {%s} in dropdown {%s}!"
528
+ % (dropdown_selector, option)
529
+ )
530
+
531
+ def flash(
532
+ self,
533
+ selector, # The CSS Selector to flash
534
+ duration=1, # (seconds) flash duration
535
+ color="44CC88", # RGB hex flash color
536
+ pause=0, # (seconds) If 0, the next action starts during flash
537
+ ):
495
538
  """Paint a quickly-vanishing dot over an element."""
496
- self.find_element(selector).flash()
539
+ selector = self.__convert_to_css_if_xpath(selector)
540
+ element = self.find_element(selector)
541
+ element.flash(duration=duration, color=color)
542
+ if pause and isinstance(pause, (int, float)):
543
+ time.sleep(pause)
544
+
545
+ def highlight(self, selector):
546
+ """Highlight an element with multi-colors."""
547
+ selector = self.__convert_to_css_if_xpath(selector)
548
+ element = self.find_element(selector)
549
+ element.flash(0.46, "44CC88")
550
+ time.sleep(0.15)
551
+ element.flash(0.42, "8844CC")
552
+ time.sleep(0.15)
553
+ element.flash(0.38, "CC8844")
554
+ time.sleep(0.15)
555
+ element.flash(0.30, "44CC88")
556
+ time.sleep(0.30)
497
557
 
498
558
  def focus(self, selector):
499
559
  self.find_element(selector).focus()
@@ -522,12 +582,10 @@ class CDPMethods():
522
582
  with suppress(Exception):
523
583
  self.loop.run_until_complete(self.page.evaluate(js_code))
524
584
 
525
- def scroll_into_view(self, selector):
526
- self.find_element(selector).scroll_into_view()
527
-
528
585
  def send_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
529
- element = self.select(selector)
530
586
  self.__slow_mode_pause_if_set()
587
+ element = self.select(selector, timeout=timeout)
588
+ self.__add_light_pause()
531
589
  if text.endswith("\n") or text.endswith("\r"):
532
590
  text = text[:-1] + "\r\n"
533
591
  element.send_keys(text)
@@ -536,8 +594,9 @@ class CDPMethods():
536
594
 
537
595
  def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
538
596
  """Similar to send_keys(), but presses keys at human speed."""
539
- element = self.select(selector)
540
597
  self.__slow_mode_pause_if_set()
598
+ element = self.select(selector, timeout=timeout)
599
+ self.__add_light_pause()
541
600
  submit = False
542
601
  if text.endswith("\n") or text.endswith("\r"):
543
602
  submit = True
@@ -553,8 +612,9 @@ class CDPMethods():
553
612
 
554
613
  def type(self, selector, text, timeout=settings.SMALL_TIMEOUT):
555
614
  """Similar to send_keys(), but clears the text field first."""
556
- element = self.select(selector)
557
615
  self.__slow_mode_pause_if_set()
616
+ element = self.select(selector, timeout=timeout)
617
+ self.__add_light_pause()
558
618
  with suppress(Exception):
559
619
  element.clear_input()
560
620
  if text.endswith("\n") or text.endswith("\r"):
@@ -563,6 +623,42 @@ class CDPMethods():
563
623
  self.__slow_mode_pause_if_set()
564
624
  self.loop.run_until_complete(self.page.wait())
565
625
 
626
+ def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT):
627
+ """Similar to send_keys(), but clears the text field first."""
628
+ self.__slow_mode_pause_if_set()
629
+ selector = self.__convert_to_css_if_xpath(selector)
630
+ self.select(selector, timeout=timeout)
631
+ self.__add_light_pause()
632
+ press_enter = False
633
+ if text.endswith("\n"):
634
+ text = text[:-1]
635
+ press_enter = True
636
+ value = js_utils.escape_quotes_if_needed(re.escape(text))
637
+ css_selector = re.escape(selector)
638
+ css_selector = js_utils.escape_quotes_if_needed(css_selector)
639
+ set_value_script = (
640
+ """m_elm = document.querySelector('%s');"""
641
+ """m_elm.value = '%s';""" % (css_selector, value)
642
+ )
643
+ self.loop.run_until_complete(self.page.evaluate(set_value_script))
644
+ the_type = self.get_element_attribute(selector, "type")
645
+ if the_type == "range":
646
+ # Some input sliders need a mouse event to trigger listeners.
647
+ with suppress(Exception):
648
+ mouse_move_script = (
649
+ """m_elm = document.querySelector('%s');"""
650
+ """m_evt = new Event('mousemove');"""
651
+ """m_elm.dispatchEvent(m_evt);""" % css_selector
652
+ )
653
+ self.loop.run_until_complete(
654
+ self.page.evaluate(mouse_move_script)
655
+ )
656
+ elif press_enter:
657
+ self.__add_light_pause()
658
+ self.send_keys(selector, "\n")
659
+ self.__slow_mode_pause_if_set()
660
+ self.loop.run_until_complete(self.page.wait())
661
+
566
662
  def evaluate(self, expression):
567
663
  """Run a JavaScript expression and return the result."""
568
664
  return self.loop.run_until_complete(
@@ -576,21 +672,30 @@ class CDPMethods():
576
672
  )
577
673
 
578
674
  def maximize(self):
579
- return self.loop.run_until_complete(
580
- self.page.maximize()
581
- )
675
+ if self.get_window()[1].window_state.value == "maximized":
676
+ return
677
+ elif self.get_window()[1].window_state.value == "minimized":
678
+ self.loop.run_until_complete(self.page.maximize())
679
+ time.sleep(0.0375)
680
+ return self.loop.run_until_complete(self.page.maximize())
582
681
 
583
682
  def minimize(self):
584
- return self.loop.run_until_complete(
585
- self.page.minimize()
586
- )
683
+ if self.get_window()[1].window_state.value != "minimized":
684
+ return self.loop.run_until_complete(self.page.minimize())
587
685
 
588
686
  def medimize(self):
589
- return self.loop.run_until_complete(
590
- self.page.medimize()
591
- )
687
+ if self.get_window()[1].window_state.value == "minimized":
688
+ self.loop.run_until_complete(self.page.medimize())
689
+ time.sleep(0.0375)
690
+ return self.loop.run_until_complete(self.page.medimize())
592
691
 
593
692
  def set_window_rect(self, x, y, width, height):
693
+ if self.get_window()[1].window_state.value == "minimized":
694
+ self.loop.run_until_complete(
695
+ self.page.set_window_size(
696
+ left=x, top=y, width=width, height=height)
697
+ )
698
+ time.sleep(0.0375)
594
699
  return self.loop.run_until_complete(
595
700
  self.page.set_window_size(
596
701
  left=x, top=y, width=width, height=height)
@@ -602,6 +707,7 @@ class CDPMethods():
602
707
  width = settings.CHROME_START_WIDTH
603
708
  height = settings.CHROME_START_HEIGHT
604
709
  self.set_window_rect(x, y, width, height)
710
+ self.__add_light_pause()
605
711
 
606
712
  def get_window(self):
607
713
  return self.loop.run_until_complete(
@@ -737,8 +843,10 @@ class CDPMethods():
737
843
  coordinates["y"] = y if y else 0
738
844
  return coordinates
739
845
 
740
- def get_element_rect(self, selector):
846
+ def get_element_rect(self, selector, timeout=settings.SMALL_TIMEOUT):
741
847
  selector = self.__convert_to_css_if_xpath(selector)
848
+ self.select(selector, timeout=timeout)
849
+ self.__add_light_pause()
742
850
  coordinates = self.loop.run_until_complete(
743
851
  self.page.js_dumps(
744
852
  """document.querySelector"""
@@ -785,7 +893,7 @@ class CDPMethods():
785
893
  e_height = element_rect["height"]
786
894
  e_x = element_rect["x"]
787
895
  e_y = element_rect["y"]
788
- return ((e_x + e_width / 2), (e_y + e_height / 2))
896
+ return ((e_x + e_width / 2.0) + 0.5, (e_y + e_height / 2.0) + 0.5)
789
897
 
790
898
  def get_document(self):
791
899
  return self.loop.run_until_complete(
@@ -798,6 +906,7 @@ class CDPMethods():
798
906
  )
799
907
 
800
908
  def get_element_attributes(self, selector):
909
+ selector = self.__convert_to_css_if_xpath(selector)
801
910
  return self.loop.run_until_complete(
802
911
  self.page.js_dumps(
803
912
  """document.querySelector('%s')"""
@@ -1013,6 +1122,156 @@ class CDPMethods():
1013
1122
  pyautogui.click(x=x, y=y)
1014
1123
 
1015
1124
  def gui_click_x_y(self, x, y, timeframe=0.25):
1125
+ gui_lock = fasteners.InterProcessLock(
1126
+ constants.MultiBrowser.PYAUTOGUILOCK
1127
+ )
1128
+ with gui_lock: # Prevent issues with multiple processes
1129
+ self.__install_pyautogui_if_missing()
1130
+ import pyautogui
1131
+ pyautogui = self.__get_configured_pyautogui(pyautogui)
1132
+ width_ratio = 1.0
1133
+ if shared_utils.is_windows():
1134
+ window_rect = self.get_window_rect()
1135
+ width = window_rect["width"]
1136
+ height = window_rect["height"]
1137
+ win_x = window_rect["x"]
1138
+ win_y = window_rect["y"]
1139
+ scr_width = pyautogui.size().width
1140
+ self.maximize()
1141
+ self.__add_light_pause()
1142
+ win_width = self.get_window_size()["width"]
1143
+ width_ratio = round(float(scr_width) / float(win_width), 2)
1144
+ width_ratio += 0.01
1145
+ if width_ratio < 0.45 or width_ratio > 2.55:
1146
+ width_ratio = 1.01
1147
+ sb_config._saved_width_ratio = width_ratio
1148
+ self.minimize()
1149
+ self.__add_light_pause()
1150
+ self.set_window_rect(win_x, win_y, width, height)
1151
+ self.__add_light_pause()
1152
+ x = x * width_ratio
1153
+ y = y * width_ratio
1154
+ self.bring_active_window_to_front()
1155
+ self.__gui_click_x_y(x, y, timeframe=timeframe, uc_lock=False)
1156
+
1157
+ def gui_click_element(self, selector, timeframe=0.25):
1158
+ self.__slow_mode_pause_if_set()
1159
+ x, y = self.get_gui_element_center(selector)
1160
+ self.__add_light_pause()
1161
+ self.gui_click_x_y(x, y, timeframe=timeframe)
1162
+ self.__slow_mode_pause_if_set()
1163
+ self.loop.run_until_complete(self.page.wait())
1164
+
1165
+ def __gui_drag_drop(self, x1, y1, x2, y2, timeframe=0.25, uc_lock=False):
1166
+ self.__install_pyautogui_if_missing()
1167
+ import pyautogui
1168
+ pyautogui = self.__get_configured_pyautogui(pyautogui)
1169
+ screen_width, screen_height = pyautogui.size()
1170
+ if x1 < 0 or y1 < 0 or x1 > screen_width or y1 > screen_height:
1171
+ raise Exception(
1172
+ "PyAutoGUI cannot drag-drop from point (%s, %s)"
1173
+ " outside screen. (Width: %s, Height: %s)"
1174
+ % (x1, y1, screen_width, screen_height)
1175
+ )
1176
+ if x2 < 0 or y2 < 0 or x2 > screen_width or y2 > screen_height:
1177
+ raise Exception(
1178
+ "PyAutoGUI cannot drag-drop to point (%s, %s)"
1179
+ " outside screen. (Width: %s, Height: %s)"
1180
+ % (x2, y2, screen_width, screen_height)
1181
+ )
1182
+ if uc_lock:
1183
+ gui_lock = fasteners.InterProcessLock(
1184
+ constants.MultiBrowser.PYAUTOGUILOCK
1185
+ )
1186
+ with gui_lock: # Prevent issues with multiple processes
1187
+ pyautogui.moveTo(x1, y1, 0.25, pyautogui.easeOutQuad)
1188
+ self.__add_light_pause()
1189
+ if "--debug" in sys.argv:
1190
+ print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x1, y1))
1191
+ pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
1192
+ else:
1193
+ # Called from a method where the gui_lock is already active
1194
+ pyautogui.moveTo(x1, y1, 0.25, pyautogui.easeOutQuad)
1195
+ self.__add_light_pause()
1196
+ if "--debug" in sys.argv:
1197
+ print(" <DEBUG> pyautogui.dragTo(%s, %s)" % (x2, y2))
1198
+ pyautogui.dragTo(x2, y2, button="left", duration=timeframe)
1199
+
1200
+ def gui_drag_drop_points(self, x1, y1, x2, y2, timeframe=0.35):
1201
+ gui_lock = fasteners.InterProcessLock(
1202
+ constants.MultiBrowser.PYAUTOGUILOCK
1203
+ )
1204
+ with gui_lock: # Prevent issues with multiple processes
1205
+ self.__install_pyautogui_if_missing()
1206
+ import pyautogui
1207
+ pyautogui = self.__get_configured_pyautogui(pyautogui)
1208
+ width_ratio = 1.0
1209
+ if shared_utils.is_windows():
1210
+ window_rect = self.get_window_rect()
1211
+ width = window_rect["width"]
1212
+ height = window_rect["height"]
1213
+ win_x = window_rect["x"]
1214
+ win_y = window_rect["y"]
1215
+ scr_width = pyautogui.size().width
1216
+ self.maximize()
1217
+ self.__add_light_pause()
1218
+ win_width = self.get_window_size()["width"]
1219
+ width_ratio = round(float(scr_width) / float(win_width), 2)
1220
+ width_ratio += 0.01
1221
+ if width_ratio < 0.45 or width_ratio > 2.55:
1222
+ width_ratio = 1.01
1223
+ sb_config._saved_width_ratio = width_ratio
1224
+ self.minimize()
1225
+ self.__add_light_pause()
1226
+ self.set_window_rect(win_x, win_y, width, height)
1227
+ self.__add_light_pause()
1228
+ x1 = x1 * width_ratio
1229
+ y1 = y1 * width_ratio
1230
+ x2 = x2 * width_ratio
1231
+ y2 = y2 * width_ratio
1232
+ self.bring_active_window_to_front()
1233
+ self.__gui_drag_drop(
1234
+ x1, y1, x2, y2, timeframe=timeframe, uc_lock=False
1235
+ )
1236
+ self.__slow_mode_pause_if_set()
1237
+ self.loop.run_until_complete(self.page.wait())
1238
+
1239
+ def gui_drag_and_drop(self, drag_selector, drop_selector, timeframe=0.35):
1240
+ self.__slow_mode_pause_if_set()
1241
+ x1, y1 = self.get_gui_element_center(drag_selector)
1242
+ self.__add_light_pause()
1243
+ x2, y2 = self.get_gui_element_center(drop_selector)
1244
+ self.__add_light_pause()
1245
+ self.gui_drag_drop_points(x1, y1, x2, y2, timeframe=timeframe)
1246
+
1247
+ def __gui_hover_x_y(self, x, y, timeframe=0.25, uc_lock=False):
1248
+ self.__install_pyautogui_if_missing()
1249
+ import pyautogui
1250
+ pyautogui = self.__get_configured_pyautogui(pyautogui)
1251
+ screen_width, screen_height = pyautogui.size()
1252
+ if x < 0 or y < 0 or x > screen_width or y > screen_height:
1253
+ raise Exception(
1254
+ "PyAutoGUI cannot hover on point (%s, %s)"
1255
+ " outside screen. (Width: %s, Height: %s)"
1256
+ % (x, y, screen_width, screen_height)
1257
+ )
1258
+ if uc_lock:
1259
+ gui_lock = fasteners.InterProcessLock(
1260
+ constants.MultiBrowser.PYAUTOGUILOCK
1261
+ )
1262
+ with gui_lock: # Prevent issues with multiple processes
1263
+ pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
1264
+ time.sleep(0.056)
1265
+ if "--debug" in sys.argv:
1266
+ print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x, y))
1267
+ else:
1268
+ # Called from a method where the gui_lock is already active
1269
+ pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
1270
+ time.sleep(0.056)
1271
+ if "--debug" in sys.argv:
1272
+ print(" <DEBUG> pyautogui.moveTo(%s, %s)" % (x, y))
1273
+
1274
+ def gui_hover_x_y(self, x, y, timeframe=0.25):
1016
1275
  gui_lock = fasteners.InterProcessLock(
1017
1276
  constants.MultiBrowser.PYAUTOGUILOCK
1018
1277
  )
@@ -1041,6 +1300,7 @@ class CDPMethods():
1041
1300
  else:
1042
1301
  scr_width = pyautogui.size().width
1043
1302
  self.maximize()
1303
+ self.__add_light_pause()
1044
1304
  win_width = self.get_window_size()["width"]
1045
1305
  width_ratio = round(float(scr_width) / float(win_width), 2)
1046
1306
  width_ratio += 0.01
@@ -1048,6 +1308,7 @@ class CDPMethods():
1048
1308
  width_ratio = 1.01
1049
1309
  sb_config._saved_width_ratio = width_ratio
1050
1310
  self.set_window_rect(win_x, win_y, width, height)
1311
+ self.__add_light_pause()
1051
1312
  self.bring_active_window_to_front()
1052
1313
  elif (
1053
1314
  shared_utils.is_windows()
@@ -1059,19 +1320,29 @@ class CDPMethods():
1059
1320
  if shared_utils.is_windows():
1060
1321
  x = x * width_ratio
1061
1322
  y = y * width_ratio
1062
- self.__gui_click_x_y(x, y, timeframe=timeframe, uc_lock=False)
1323
+ self.__gui_hover_x_y(x, y, timeframe=timeframe, uc_lock=False)
1063
1324
  return
1064
1325
  self.bring_active_window_to_front()
1065
- self.__gui_click_x_y(x, y, timeframe=timeframe, uc_lock=False)
1326
+ self.__gui_hover_x_y(x, y, timeframe=timeframe, uc_lock=False)
1066
1327
 
1067
- def gui_click_element(self, selector, timeframe=0.25):
1328
+ def gui_hover_element(self, selector, timeframe=0.25):
1068
1329
  self.__slow_mode_pause_if_set()
1069
1330
  x, y = self.get_gui_element_center(selector)
1070
1331
  self.__add_light_pause()
1071
- self.gui_click_x_y(x, y, timeframe=timeframe)
1332
+ self.__gui_hover_x_y(x, y, timeframe=timeframe)
1072
1333
  self.__slow_mode_pause_if_set()
1073
1334
  self.loop.run_until_complete(self.page.wait())
1074
1335
 
1336
+ def gui_hover_and_click(self, hover_selector, click_selector):
1337
+ gui_lock = fasteners.InterProcessLock(
1338
+ constants.MultiBrowser.PYAUTOGUILOCK
1339
+ )
1340
+ with gui_lock:
1341
+ self.gui_hover_element(hover_selector)
1342
+ time.sleep(0.15)
1343
+ self.gui_hover_element(click_selector)
1344
+ self.click(click_selector)
1345
+
1075
1346
  def internalize_links(self):
1076
1347
  """All `target="_blank"` links become `target="_self"`.
1077
1348
  This prevents those links from opening in a new tab."""
@@ -1079,24 +1350,30 @@ class CDPMethods():
1079
1350
 
1080
1351
  def is_checked(self, selector):
1081
1352
  """Return True if checkbox (or radio button) is checked."""
1353
+ selector = self.__convert_to_css_if_xpath(selector)
1082
1354
  self.find_element(selector, timeout=settings.SMALL_TIMEOUT)
1083
1355
  return self.get_element_attribute(selector, "checked")
1084
1356
 
1085
1357
  def is_selected(self, selector):
1358
+ selector = self.__convert_to_css_if_xpath(selector)
1086
1359
  return self.is_checked(selector)
1087
1360
 
1088
1361
  def check_if_unchecked(self, selector):
1362
+ selector = self.__convert_to_css_if_xpath(selector)
1089
1363
  if not self.is_checked(selector):
1090
1364
  self.click(selector)
1091
1365
 
1092
1366
  def select_if_unselected(self, selector):
1367
+ selector = self.__convert_to_css_if_xpath(selector)
1093
1368
  self.check_if_unchecked(selector)
1094
1369
 
1095
1370
  def uncheck_if_checked(self, selector):
1371
+ selector = self.__convert_to_css_if_xpath(selector)
1096
1372
  if self.is_checked(selector):
1097
1373
  self.click(selector)
1098
1374
 
1099
1375
  def unselect_if_selected(self, selector):
1376
+ selector = self.__convert_to_css_if_xpath(selector)
1100
1377
  self.uncheck_if_checked(selector)
1101
1378
 
1102
1379
  def is_element_present(self, selector):
@@ -1105,32 +1382,22 @@ class CDPMethods():
1105
1382
  return True
1106
1383
  except Exception:
1107
1384
  return False
1108
- selector = self.__convert_to_css_if_xpath(selector)
1109
- element = self.loop.run_until_complete(
1110
- self.page.js_dumps(
1111
- """document.querySelector('%s')"""
1112
- % js_utils.escape_quotes_if_needed(re.escape(selector))
1113
- )
1114
- )
1115
- return element is not None
1116
1385
 
1117
1386
  def is_element_visible(self, selector):
1118
1387
  selector = self.__convert_to_css_if_xpath(selector)
1119
1388
  element = None
1120
1389
  if ":contains(" not in selector:
1121
1390
  try:
1122
- element = self.loop.run_until_complete(
1123
- self.page.js_dumps(
1124
- """window.getComputedStyle(document.querySelector"""
1125
- """('%s'))"""
1126
- % js_utils.escape_quotes_if_needed(re.escape(selector))
1127
- )
1128
- )
1391
+ element = self.select(selector, timeout=0.01)
1129
1392
  except Exception:
1130
1393
  return False
1131
1394
  if not element:
1132
1395
  return False
1133
- return element.get("display") != "none"
1396
+ try:
1397
+ position = element.get_position()
1398
+ return (position.width != 0 or position.height != 0)
1399
+ except Exception:
1400
+ return False
1134
1401
  else:
1135
1402
  with suppress(Exception):
1136
1403
  tag_name = selector.split(":contains(")[0].split(" ")[-1]
@@ -1160,9 +1427,66 @@ class CDPMethods():
1160
1427
  raise Exception("Element {%s} not found!" % selector)
1161
1428
  return True
1162
1429
 
1430
+ def assert_element_absent(self, selector, timeout=settings.SMALL_TIMEOUT):
1431
+ start_ms = time.time() * 1000.0
1432
+ stop_ms = start_ms + (timeout * 1000.0)
1433
+ for i in range(int(timeout * 10)):
1434
+ if not self.is_element_present(selector):
1435
+ return True
1436
+ now_ms = time.time() * 1000.0
1437
+ if now_ms >= stop_ms:
1438
+ break
1439
+ time.sleep(0.1)
1440
+ plural = "s"
1441
+ if timeout == 1:
1442
+ plural = ""
1443
+ raise Exception(
1444
+ "Element {%s} was still present after %s second%s!"
1445
+ % (selector, timeout, plural)
1446
+ )
1447
+
1448
+ def assert_element_not_visible(
1449
+ self, selector, timeout=settings.SMALL_TIMEOUT
1450
+ ):
1451
+ start_ms = time.time() * 1000.0
1452
+ stop_ms = start_ms + (timeout * 1000.0)
1453
+ for i in range(int(timeout * 10)):
1454
+ if not self.is_element_present(selector):
1455
+ return True
1456
+ elif not self.is_element_visible(selector):
1457
+ return True
1458
+ now_ms = time.time() * 1000.0
1459
+ if now_ms >= stop_ms:
1460
+ break
1461
+ time.sleep(0.1)
1462
+ plural = "s"
1463
+ if timeout == 1:
1464
+ plural = ""
1465
+ raise Exception(
1466
+ "Element {%s} was still visible after %s second%s!"
1467
+ % (selector, timeout, plural)
1468
+ )
1469
+
1470
+ def assert_title(self, title):
1471
+ expected = title.strip()
1472
+ actual = self.get_title().strip()
1473
+ error = (
1474
+ "Expected page title [%s] does not match the actual title [%s]!"
1475
+ )
1476
+ try:
1477
+ if expected != actual:
1478
+ raise Exception(error % (expected, actual))
1479
+ except Exception:
1480
+ time.sleep(2)
1481
+ expected = title.strip()
1482
+ actual = self.get_title().strip()
1483
+ if expected != actual:
1484
+ raise Exception(error % (expected, actual))
1485
+
1163
1486
  def assert_text(
1164
1487
  self, text, selector="html", timeout=settings.SMALL_TIMEOUT
1165
1488
  ):
1489
+ text = text.strip()
1166
1490
  element = None
1167
1491
  try:
1168
1492
  element = self.select(selector, timeout=timeout)
@@ -1180,6 +1504,7 @@ class CDPMethods():
1180
1504
  def assert_exact_text(
1181
1505
  self, text, selector="html", timeout=settings.SMALL_TIMEOUT
1182
1506
  ):
1507
+ text = text.strip()
1183
1508
  element = None
1184
1509
  try:
1185
1510
  element = self.select(selector, timeout=timeout)
@@ -1197,15 +1522,36 @@ class CDPMethods():
1197
1522
  % (text, element.text_all, selector)
1198
1523
  )
1199
1524
 
1200
- def scroll_down(self, amount=25):
1201
- self.loop.run_until_complete(
1202
- self.page.scroll_down(amount)
1203
- )
1525
+ def scroll_into_view(self, selector):
1526
+ self.find_element(selector).scroll_into_view()
1527
+ self.loop.run_until_complete(self.page.wait())
1528
+
1529
+ def scroll_to_y(self, y):
1530
+ y = int(y)
1531
+ js_code = "window.scrollTo(0, %s);" % y
1532
+ with suppress(Exception):
1533
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1534
+ self.loop.run_until_complete(self.page.wait())
1535
+
1536
+ def scroll_to_top(self):
1537
+ js_code = "window.scrollTo(0, 0);"
1538
+ with suppress(Exception):
1539
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1540
+ self.loop.run_until_complete(self.page.wait())
1541
+
1542
+ def scroll_to_bottom(self):
1543
+ js_code = "window.scrollTo(0, 10000);"
1544
+ with suppress(Exception):
1545
+ self.loop.run_until_complete(self.page.evaluate(js_code))
1546
+ self.loop.run_until_complete(self.page.wait())
1204
1547
 
1205
1548
  def scroll_up(self, amount=25):
1206
- self.loop.run_until_complete(
1207
- self.page.scroll_up(amount)
1208
- )
1549
+ self.loop.run_until_complete(self.page.scroll_up(amount))
1550
+ self.loop.run_until_complete(self.page.wait())
1551
+
1552
+ def scroll_down(self, amount=25):
1553
+ self.loop.run_until_complete(self.page.scroll_down(amount))
1554
+ self.loop.run_until_complete(self.page.wait())
1209
1555
 
1210
1556
  def save_screenshot(self, name, folder=None, selector=None):
1211
1557
  filename = name