@@ -252,6 +252,45 @@ def select_all(self, selector, timeout=settings.SMALL_TIMEOUT):
252252 def find_elements (self , selector , timeout = settings .SMALL_TIMEOUT ):
253253 return self .select_all (selector , timeout = timeout )
254254
255+ def find_visible_elements (self , selector , timeout = settings .SMALL_TIMEOUT ):
256+ visible_elements = []
257+ elements = self .select_all (selector , timeout = timeout )
258+ for element in elements :
259+ with suppress (Exception ):
260+ position = element .get_position ()
261+ if (position .width != 0 or position .height != 0 ):
262+ visible_elements .append (element )
263+ return visible_elements
264+
265+ def click_nth_element (self , selector , number ):
266+ elements = self .select_all (selector )
267+ if len (elements ) < number :
268+ raise Exception (
269+ "Not enough matching {%s} elements to "
270+ "click number %s!" % (selector , number )
271+ )
272+ number = number - 1
273+ if number < 0 :
274+ number = 0
275+ element = elements [number ]
276+ element .click ()
277+
278+ def click_nth_visible_element (self , selector , number ):
279+ """Finds all matching page elements and clicks the nth visible one.
280+ Example: self.click_nth_visible_element('[type="checkbox"]', 5)
281+ (Clicks the 5th visible checkbox on the page.)"""
282+ elements = self .find_visible_elements (selector )
283+ if len (elements ) < number :
284+ raise Exception (
285+ "Not enough matching {%s} elements to "
286+ "click number %s!" % (selector , number )
287+ )
288+ number = number - 1
289+ if number < 0 :
290+ number = 0
291+ element = elements [number ]
292+ element .click ()
293+
255294 def click_link (self , link_text ):
256295 self .find_elements_by_text (link_text , "a" )[0 ].click ()
257296
@@ -479,18 +518,36 @@ def click_if_visible(self, selector):
479518 self .__slow_mode_pause_if_set ()
480519 self .loop .run_until_complete (self .page .wait ())
481520
482- def click_visible_elements (self , selector ):
521+ def click_visible_elements (self , selector , limit = 0 ):
522+ """Finds all matching page elements and clicks visible ones in order.
523+ If a click reloads or opens a new page, the clicking will stop.
524+ If no matching elements appear, an Exception will be raised.
525+ If "limit" is set and > 0, will only click that many elements.
526+ Also clicks elements that become visible from previous clicks.
527+ Works best for actions such as clicking all checkboxes on a page.
528+ Example: self.click_visible_elements('input[type="checkbox"]')"""
483529 elements = self .select_all (selector )
530+ click_count = 0
484531 for element in elements :
532+ if limit and limit > 0 and click_count >= limit :
533+ return
485534 try :
486- position = element .get_position ()
487- if (position .width != 0 or position .height != 0 ):
535+ width = 0
536+ height = 0
537+ try :
538+ position = element .get_position ()
539+ width = position .width
540+ height = position .height
541+ except Exception :
542+ continue
543+ if (width != 0 or height != 0 ):
488544 element .click ()
545+ click_count += 1
489546 time .sleep (0.0375 )
490547 self .__slow_mode_pause_if_set ()
491548 self .loop .run_until_complete (self .page .wait ())
492549 except Exception :
493- pass
550+ break
494551
495552 def mouse_click (self , selector , timeout = settings .SMALL_TIMEOUT ):
496553 """(Attempt simulating a mouse click)"""
@@ -1238,6 +1295,7 @@ def gui_drag_drop_points(self, x1, y1, x2, y2, timeframe=0.35):
12381295
12391296 def gui_drag_and_drop (self , drag_selector , drop_selector , timeframe = 0.35 ):
12401297 self .__slow_mode_pause_if_set ()
1298+ self .bring_active_window_to_front ()
12411299 x1 , y1 = self .get_gui_element_center (drag_selector )
12421300 self .__add_light_pause ()
12431301 x2 , y2 = self .get_gui_element_center (drop_selector )
@@ -1327,17 +1385,22 @@ def gui_hover_x_y(self, x, y, timeframe=0.25):
13271385
13281386 def gui_hover_element (self , selector , timeframe = 0.25 ):
13291387 self .__slow_mode_pause_if_set ()
1330- x , y = self .get_gui_element_center (selector )
1331- self .__add_light_pause ()
1332- self .__gui_hover_x_y (x , y , timeframe = timeframe )
1333- self .__slow_mode_pause_if_set ()
1388+ element_rect = self .get_gui_element_rect (selector )
1389+ width = element_rect ["width" ]
1390+ height = element_rect ["height" ]
1391+ if width > 0 and height > 0 :
1392+ x , y = self .get_gui_element_center (selector )
1393+ self .bring_active_window_to_front ()
1394+ self .__gui_hover_x_y (x , y , timeframe = timeframe )
1395+ self .__slow_mode_pause_if_set ()
13341396 self .loop .run_until_complete (self .page .wait ())
13351397
13361398 def gui_hover_and_click (self , hover_selector , click_selector ):
13371399 gui_lock = fasteners .InterProcessLock (
13381400 constants .MultiBrowser .PYAUTOGUILOCK
13391401 )
13401402 with gui_lock :
1403+ self .bring_active_window_to_front ()
13411404 self .gui_hover_element (hover_selector )
13421405 time .sleep (0.15 )
13431406 self .gui_hover_element (click_selector )
0 commit comments