seleniumbase 4.32.9__py3-none-any.whl → 4.32.10__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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