@@ -268,6 +268,7 @@ def click_nth_element(self, selector, number):
268
268
if number < 0 :
269
269
number = 0
270
270
element = elements [number ]
271
+ element .scroll_into_view ()
271
272
element .click ()
272
273
273
274
def click_nth_visible_element (self , selector , number ):
@@ -284,6 +285,7 @@ def click_nth_visible_element(self, selector, number):
284
285
if number < 0 :
285
286
number = 0
286
287
element = elements [number ]
288
+ element .scroll_into_view ()
287
289
element .click ()
288
290
289
291
def click_link (self , link_text ):
@@ -311,6 +313,13 @@ def __click(self, element):
311
313
return result
312
314
313
315
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
314
323
return (
315
324
self .loop .run_until_complete (
316
325
element .flash_async (* args , ** kwargs )
@@ -382,9 +391,9 @@ def __save_to_dom(self, element):
382
391
)
383
392
384
393
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
388
397
389
398
def __select_option (self , element ):
390
399
return (
@@ -431,6 +440,18 @@ def __get_js_attributes(self, element):
431
440
self .loop .run_until_complete (element .get_js_attributes_async ())
432
441
)
433
442
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
+
434
455
def tile_windows (self , windows = None , max_columns = 0 ):
435
456
"""Tile windows and return the grid of tiled windows."""
436
457
driver = self .driver
@@ -504,7 +525,7 @@ def get_active_element_css(self):
504
525
def click (self , selector , timeout = settings .SMALL_TIMEOUT ):
505
526
self .__slow_mode_pause_if_set ()
506
527
element = self .find_element (selector , timeout = timeout )
507
- self . __add_light_pause ()
528
+ element . scroll_into_view ()
508
529
element .click ()
509
530
self .__slow_mode_pause_if_set ()
510
531
self .loop .run_until_complete (self .page .wait ())
@@ -518,7 +539,9 @@ def click_active_element(self):
518
539
519
540
def click_if_visible (self , selector ):
520
541
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 ()
522
545
self .__slow_mode_pause_if_set ()
523
546
self .loop .run_until_complete (self .page .wait ())
524
547
@@ -545,9 +568,10 @@ def click_visible_elements(self, selector, limit=0):
545
568
except Exception :
546
569
continue
547
570
if (width != 0 or height != 0 ):
571
+ element .scroll_into_view ()
548
572
element .click ()
549
573
click_count += 1
550
- time .sleep (0.044 )
574
+ time .sleep (0.042 )
551
575
self .__slow_mode_pause_if_set ()
552
576
self .loop .run_until_complete (self .page .wait ())
553
577
except Exception :
@@ -557,7 +581,7 @@ def mouse_click(self, selector, timeout=settings.SMALL_TIMEOUT):
557
581
"""(Attempt simulating a mouse click)"""
558
582
self .__slow_mode_pause_if_set ()
559
583
element = self .find_element (selector , timeout = timeout )
560
- self . __add_light_pause ()
584
+ element . scroll_into_view ()
561
585
element .mouse_click ()
562
586
self .__slow_mode_pause_if_set ()
563
587
self .loop .run_until_complete (self .page .wait ())
@@ -579,6 +603,7 @@ def get_nested_element(self, parent_selector, selector):
579
603
580
604
def select_option_by_text (self , dropdown_selector , option ):
581
605
element = self .find_element (dropdown_selector )
606
+ element .scroll_into_view ()
582
607
options = element .query_selector_all ("option" )
583
608
for found_option in options :
584
609
if found_option .text .strip () == option .strip ():
@@ -599,25 +624,33 @@ def flash(
599
624
"""Paint a quickly-vanishing dot over an element."""
600
625
selector = self .__convert_to_css_if_xpath (selector )
601
626
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 )
603
631
if pause and isinstance (pause , (int , float )):
604
632
time .sleep (pause )
605
633
606
634
def highlight (self , selector ):
607
635
"""Highlight an element with multi-colors."""
608
636
selector = self .__convert_to_css_if_xpath (selector )
609
637
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 )
611
642
time .sleep (0.15 )
612
- element .flash (0.42 , "8844CC" )
643
+ element .flash (0.42 , "8844CC" , x_offset , y_offset )
613
644
time .sleep (0.15 )
614
- element .flash (0.38 , "CC8844" )
645
+ element .flash (0.38 , "CC8844" , x_offset , y_offset )
615
646
time .sleep (0.15 )
616
- element .flash (0.30 , "44CC88" )
647
+ element .flash (0.30 , "44CC88" , x_offset , y_offset )
617
648
time .sleep (0.30 )
618
649
619
650
def focus (self , selector ):
620
- self .find_element (selector ).focus ()
651
+ element = self .find_element (selector )
652
+ element .scroll_into_view ()
653
+ element .focus ()
621
654
622
655
def highlight_overlay (self , selector ):
623
656
self .find_element (selector ).highlight_overlay ()
@@ -646,7 +679,7 @@ def remove_elements(self, selector):
646
679
def send_keys (self , selector , text , timeout = settings .SMALL_TIMEOUT ):
647
680
self .__slow_mode_pause_if_set ()
648
681
element = self .select (selector , timeout = timeout )
649
- self . __add_light_pause ()
682
+ element . scroll_into_view ()
650
683
if text .endswith ("\n " ) or text .endswith ("\r " ):
651
684
text = text [:- 1 ] + "\r \n "
652
685
element .send_keys (text )
@@ -657,7 +690,7 @@ def press_keys(self, selector, text, timeout=settings.SMALL_TIMEOUT):
657
690
"""Similar to send_keys(), but presses keys at human speed."""
658
691
self .__slow_mode_pause_if_set ()
659
692
element = self .select (selector , timeout = timeout )
660
- self . __add_light_pause ()
693
+ element . scroll_into_view ()
661
694
submit = False
662
695
if text .endswith ("\n " ) or text .endswith ("\r " ):
663
696
submit = True
@@ -675,7 +708,7 @@ def type(self, selector, text, timeout=settings.SMALL_TIMEOUT):
675
708
"""Similar to send_keys(), but clears the text field first."""
676
709
self .__slow_mode_pause_if_set ()
677
710
element = self .select (selector , timeout = timeout )
678
- self . __add_light_pause ()
711
+ element . scroll_into_view ()
679
712
with suppress (Exception ):
680
713
element .clear_input ()
681
714
if text .endswith ("\n " ) or text .endswith ("\r " ):
@@ -688,8 +721,8 @@ def set_value(self, selector, text, timeout=settings.SMALL_TIMEOUT):
688
721
"""Similar to send_keys(), but clears the text field first."""
689
722
self .__slow_mode_pause_if_set ()
690
723
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 ()
693
726
press_enter = False
694
727
if text .endswith ("\n " ):
695
728
text = text [:- 1 ]
@@ -1655,38 +1688,52 @@ def assert_url_contains(self, substring):
1655
1688
raise Exception (error % (expected , actual ))
1656
1689
1657
1690
def assert_text (
1658
- self , text , selector = "html " , timeout = settings .SMALL_TIMEOUT
1691
+ self , text , selector = "body " , timeout = settings .SMALL_TIMEOUT
1659
1692
):
1693
+ start_ms = time .time () * 1000.0
1694
+ stop_ms = start_ms + (timeout * 1000.0 )
1660
1695
text = text .strip ()
1661
1696
element = None
1662
1697
try :
1663
1698
element = self .find_element (selector , timeout = timeout )
1664
1699
except Exception :
1665
1700
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 )
1667
1704
if text in element .text_all :
1668
1705
return True
1706
+ now_ms = time .time () * 1000.0
1707
+ if now_ms >= stop_ms :
1708
+ break
1669
1709
time .sleep (0.1 )
1670
1710
raise Exception (
1671
1711
"Text {%s} not found in {%s}! Actual text: {%s}"
1672
1712
% (text , selector , element .text_all )
1673
1713
)
1674
1714
1675
1715
def assert_exact_text (
1676
- self , text , selector = "html " , timeout = settings .SMALL_TIMEOUT
1716
+ self , text , selector = "body " , timeout = settings .SMALL_TIMEOUT
1677
1717
):
1718
+ start_ms = time .time () * 1000.0
1719
+ stop_ms = start_ms + (timeout * 1000.0 )
1678
1720
text = text .strip ()
1679
1721
element = None
1680
1722
try :
1681
1723
element = self .select (selector , timeout = timeout )
1682
1724
except Exception :
1683
1725
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 )
1685
1729
if (
1686
1730
self .is_element_visible (selector )
1687
1731
and text .strip () == element .text_all .strip ()
1688
1732
):
1689
1733
return True
1734
+ now_ms = time .time () * 1000.0
1735
+ if now_ms >= stop_ms :
1736
+ break
1690
1737
time .sleep (0.1 )
1691
1738
raise Exception (
1692
1739
"Expected Text {%s}, is not equal to {%s} in {%s}!"
@@ -1727,26 +1774,31 @@ def scroll_to_y(self, y):
1727
1774
with suppress (Exception ):
1728
1775
self .loop .run_until_complete (self .page .evaluate (js_code ))
1729
1776
self .loop .run_until_complete (self .page .wait ())
1777
+ self .__add_light_pause ()
1730
1778
1731
1779
def scroll_to_top (self ):
1732
1780
js_code = "window.scrollTo(0, 0);"
1733
1781
with suppress (Exception ):
1734
1782
self .loop .run_until_complete (self .page .evaluate (js_code ))
1735
1783
self .loop .run_until_complete (self .page .wait ())
1784
+ self .__add_light_pause ()
1736
1785
1737
1786
def scroll_to_bottom (self ):
1738
1787
js_code = "window.scrollTo(0, 10000);"
1739
1788
with suppress (Exception ):
1740
1789
self .loop .run_until_complete (self .page .evaluate (js_code ))
1741
1790
self .loop .run_until_complete (self .page .wait ())
1791
+ self .__add_light_pause ()
1742
1792
1743
1793
def scroll_up (self , amount = 25 ):
1744
1794
self .loop .run_until_complete (self .page .scroll_up (amount ))
1745
1795
self .loop .run_until_complete (self .page .wait ())
1796
+ self .__add_light_pause ()
1746
1797
1747
1798
def scroll_down (self , amount = 25 ):
1748
1799
self .loop .run_until_complete (self .page .scroll_down (amount ))
1749
1800
self .loop .run_until_complete (self .page .wait ())
1801
+ self .__add_light_pause ()
1750
1802
1751
1803
def save_screenshot (self , name , folder = None , selector = None ):
1752
1804
filename = name
0 commit comments