@@ -268,6 +268,7 @@ def click_nth_element(self, selector, number):
268268 if number < 0 :
269269 number = 0
270270 element = elements [number ]
271+ element .scroll_into_view ()
271272 element .click ()
272273
273274 def click_nth_visible_element (self , selector , number ):
@@ -284,6 +285,7 @@ def click_nth_visible_element(self, selector, number):
284285 if number < 0 :
285286 number = 0
286287 element = elements [number ]
288+ element .scroll_into_view ()
287289 element .click ()
288290
289291 def click_link (self , link_text ):
@@ -311,6 +313,13 @@ def __click(self, element):
311313 return result
312314
313315 def __flash (self , element , * args , ** kwargs ):
316+ element .scroll_into_view ()
317+ if len (args ) < 3 and "x_offset" not in kwargs :
318+ x_offset = self .__get_x_scroll_offset ()
319+ kwargs ["x_offset" ] = x_offset
320+ if len (args ) < 3 and "y_offset" not in kwargs :
321+ y_offset = self .__get_y_scroll_offset ()
322+ kwargs ["y_offset" ] = y_offset
314323 return (
315324 self .loop .run_until_complete (
316325 element .flash_async (* args , ** kwargs )
@@ -382,9 +391,9 @@ def __save_to_dom(self, element):
382391 )
383392
384393 def __scroll_into_view (self , element ):
385- return (
386- self .loop . run_until_complete ( element . scroll_into_view_async () )
387- )
394+ self . loop . run_until_complete ( element . scroll_into_view_async ())
395+ self .__add_light_pause ( )
396+ return None
388397
389398 def __select_option (self , element ):
390399 return (
@@ -431,6 +440,18 @@ def __get_js_attributes(self, element):
431440 self .loop .run_until_complete (element .get_js_attributes_async ())
432441 )
433442
443+ def __get_x_scroll_offset (self ):
444+ x_scroll_offset = self .loop .run_until_complete (
445+ self .page .evaluate ("window.pageXOffset" )
446+ )
447+ return x_scroll_offset or 0
448+
449+ def __get_y_scroll_offset (self ):
450+ y_scroll_offset = self .loop .run_until_complete (
451+ self .page .evaluate ("window.pageYOffset" )
452+ )
453+ return y_scroll_offset or 0
454+
434455 def tile_windows (self , windows = None , max_columns = 0 ):
435456 """Tile windows and return the grid of tiled windows."""
436457 driver = self .driver
@@ -504,7 +525,7 @@ def get_active_element_css(self):
504525 def click (self , selector , timeout = settings .SMALL_TIMEOUT ):
505526 self .__slow_mode_pause_if_set ()
506527 element = self .find_element (selector , timeout = timeout )
507- self . __add_light_pause ()
528+ element . scroll_into_view ()
508529 element .click ()
509530 self .__slow_mode_pause_if_set ()
510531 self .loop .run_until_complete (self .page .wait ())
@@ -518,7 +539,9 @@ def click_active_element(self):
518539
519540 def click_if_visible (self , selector ):
520541 if self .is_element_visible (selector ):
521- self .find_element (selector ).click ()
542+ element = self .find_element (selector )
543+ element .scroll_into_view ()
544+ element .click ()
522545 self .__slow_mode_pause_if_set ()
523546 self .loop .run_until_complete (self .page .wait ())
524547
@@ -545,9 +568,10 @@ def click_visible_elements(self, selector, limit=0):
545568 except Exception :
546569 continue
547570 if (width != 0 or height != 0 ):
571+ element .scroll_into_view ()
548572 element .click ()
549573 click_count += 1
550- time .sleep (0.044 )
574+ time .sleep (0.042 )
551575 self .__slow_mode_pause_if_set ()
552576 self .loop .run_until_complete (self .page .wait ())
553577 except Exception :
@@ -557,7 +581,7 @@ def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT):
557581 """(Attempt simulating a mouse click)"""
558582 self .__slow_mode_pause_if_set ()
559583 element = self .find_element (selector , timeout = timeout )
560- self . __add_light_pause ()
584+ element . scroll_into_view ()
561585 element .mouse_click ()
562586 self .__slow_mode_pause_if_set ()
563587 self .loop .run_until_complete (self .page .wait ())
@@ -579,6 +603,7 @@ def get_nested_element(self, parent_selector, selector):
579603
580604 def select_option_by_text (self , dropdown_selector , option ):
581605 element = self .find_element (dropdown_selector )
606+ element .scroll_into_view ()
582607 options = element .query_selector_all ("option" )
583608 for found_option in options :
584609 if found_option .text .strip () == option .strip ():
@@ -599,25 +624,33 @@ def flash(
599624 """Paint a quickly-vanishing dot over an element."""
600625 selector = self .__convert_to_css_if_xpath (selector )
601626 element = self .find_element (selector )
602- element .flash (duration = duration , color = color )
627+ element .scroll_into_view ()
628+ x_offset = self .__get_x_scroll_offset ()
629+ y_offset = self .__get_y_scroll_offset ()
630+ element .flash (duration , color , x_offset , y_offset )
603631 if pause and isinstance (pause , (int , float )):
604632 time .sleep (pause )
605633
606634 def highlight (self , selector ):
607635 """Highlight an element with multi-colors."""
608636 selector = self .__convert_to_css_if_xpath (selector )
609637 element = self .find_element (selector )
610- element .flash (0.46 , "44CC88" )
638+ element .scroll_into_view ()
639+ x_offset = self .__get_x_scroll_offset ()
640+ y_offset = self .__get_y_scroll_offset ()
641+ element .flash (0.46 , "44CC88" , x_offset , y_offset )
611642 time .sleep (0.15 )
612- element .flash (0.42 , "8844CC" )
643+ element .flash (0.42 , "8844CC" , x_offset , y_offset )
613644 time .sleep (0.15 )
614- element .flash (0.38 , "CC8844" )
645+ element .flash (0.38 , "CC8844" , x_offset , y_offset )
615646 time .sleep (0.15 )
616- element .flash (0.30 , "44CC88" )
647+ element .flash (0.30 , "44CC88" , x_offset , y_offset )
617648 time .sleep (0.30 )
618649
619650 def focus (self , selector ):
620- self .find_element (selector ).focus ()
651+ element = self .find_element (selector )
652+ element .scroll_into_view ()
653+ element .focus ()
621654
622655 def highlight_overlay (self , selector ):
623656 self .find_element (selector ).highlight_overlay ()
@@ -646,7 +679,7 @@ def remove_elements(self, selector):
646679 def send_keys (self , selector , text , timeout = settings .SMALL_TIMEOUT ):
647680 self .__slow_mode_pause_if_set ()
648681 element = self .select (selector , timeout = timeout )
649- self . __add_light_pause ()
682+ element . scroll_into_view ()
650683 if text .endswith ("\n " ) or text .endswith ("\r " ):
651684 text = text [:- 1 ] + "\r \n "
652685 element .send_keys (text )
@@ -657,7 +690,7 @@ def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
657690 """Similar to send_keys(), but presses keys at human speed."""
658691 self .__slow_mode_pause_if_set ()
659692 element = self .select (selector , timeout = timeout )
660- self . __add_light_pause ()
693+ element . scroll_into_view ()
661694 submit = False
662695 if text .endswith ("\n " ) or text .endswith ("\r " ):
663696 submit = True
@@ -675,7 +708,7 @@ def type(self, selector, text, timeout=settings.SMALL_TIMEOUT):
675708 """Similar to send_keys(), but clears the text field first."""
676709 self .__slow_mode_pause_if_set ()
677710 element = self .select (selector , timeout = timeout )
678- self . __add_light_pause ()
711+ element . scroll_into_view ()
679712 with suppress (Exception ):
680713 element .clear_input ()
681714 if text .endswith ("\n " ) or text .endswith ("\r " ):
@@ -688,8 +721,8 @@ def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT):
688721 """Similar to send_keys(), but clears the text field first."""
689722 self .__slow_mode_pause_if_set ()
690723 selector = self .__convert_to_css_if_xpath (selector )
691- self .select (selector , timeout = timeout )
692- self . __add_light_pause ()
724+ element = self .select (selector , timeout = timeout )
725+ element . scroll_into_view ()
693726 press_enter = False
694727 if text .endswith ("\n " ):
695728 text = text [:- 1 ]
@@ -1655,38 +1688,52 @@ def assert_url_contains(self, substring):
16551688 raise Exception (error % (expected , actual ))
16561689
16571690 def assert_text (
1658- self , text , selector = "html " , timeout = settings .SMALL_TIMEOUT
1691+ self , text , selector = "body " , timeout = settings .SMALL_TIMEOUT
16591692 ):
1693+ start_ms = time .time () * 1000.0
1694+ stop_ms = start_ms + (timeout * 1000.0 )
16601695 text = text .strip ()
16611696 element = None
16621697 try :
16631698 element = self .find_element (selector , timeout = timeout )
16641699 except Exception :
16651700 raise Exception ("Element {%s} not found!" % selector )
1666- for i in range (30 ):
1701+ for i in range (int (timeout * 10 )):
1702+ with suppress (Exception ):
1703+ element = self .find_element (selector , timeout = 0.1 )
16671704 if text in element .text_all :
16681705 return True
1706+ now_ms = time .time () * 1000.0
1707+ if now_ms >= stop_ms :
1708+ break
16691709 time .sleep (0.1 )
16701710 raise Exception (
16711711 "Text {%s} not found in {%s}! Actual text: {%s}"
16721712 % (text , selector , element .text_all )
16731713 )
16741714
16751715 def assert_exact_text (
1676- self , text , selector = "html " , timeout = settings .SMALL_TIMEOUT
1716+ self , text , selector = "body " , timeout = settings .SMALL_TIMEOUT
16771717 ):
1718+ start_ms = time .time () * 1000.0
1719+ stop_ms = start_ms + (timeout * 1000.0 )
16781720 text = text .strip ()
16791721 element = None
16801722 try :
16811723 element = self .select (selector , timeout = timeout )
16821724 except Exception :
16831725 raise Exception ("Element {%s} not found!" % selector )
1684- for i in range (30 ):
1726+ for i in range (int (timeout * 10 )):
1727+ with suppress (Exception ):
1728+ element = self .select (selector , timeout = 0.1 )
16851729 if (
16861730 self .is_element_visible (selector )
16871731 and text .strip () == element .text_all .strip ()
16881732 ):
16891733 return True
1734+ now_ms = time .time () * 1000.0
1735+ if now_ms >= stop_ms :
1736+ break
16901737 time .sleep (0.1 )
16911738 raise Exception (
16921739 "Expected Text {%s}, is not equal to {%s} in {%s}!"
@@ -1727,26 +1774,31 @@ def scroll_to_y(self, y):
17271774 with suppress (Exception ):
17281775 self .loop .run_until_complete (self .page .evaluate (js_code ))
17291776 self .loop .run_until_complete (self .page .wait ())
1777+ self .__add_light_pause ()
17301778
17311779 def scroll_to_top (self ):
17321780 js_code = "window.scrollTo(0, 0);"
17331781 with suppress (Exception ):
17341782 self .loop .run_until_complete (self .page .evaluate (js_code ))
17351783 self .loop .run_until_complete (self .page .wait ())
1784+ self .__add_light_pause ()
17361785
17371786 def scroll_to_bottom (self ):
17381787 js_code = "window.scrollTo(0, 10000);"
17391788 with suppress (Exception ):
17401789 self .loop .run_until_complete (self .page .evaluate (js_code ))
17411790 self .loop .run_until_complete (self .page .wait ())
1791+ self .__add_light_pause ()
17421792
17431793 def scroll_up (self , amount = 25 ):
17441794 self .loop .run_until_complete (self .page .scroll_up (amount ))
17451795 self .loop .run_until_complete (self .page .wait ())
1796+ self .__add_light_pause ()
17461797
17471798 def scroll_down (self , amount = 25 ):
17481799 self .loop .run_until_complete (self .page .scroll_down (amount ))
17491800 self .loop .run_until_complete (self .page .wait ())
1801+ self .__add_light_pause ()
17501802
17511803 def save_screenshot (self , name , folder = None , selector = None ):
17521804 filename = name
0 commit comments