@@ -707,6 +707,111 @@ def wait_for_attribute(
707
707
return element
708
708
709
709
710
+ def wait_for_element_clickable (
711
+ driver ,
712
+ selector ,
713
+ by = "css selector" ,
714
+ timeout = settings .LARGE_TIMEOUT ,
715
+ original_selector = None ,
716
+ ):
717
+ """
718
+ Searches for the specified element by the given selector. Returns the
719
+ element object if the element is present, visible, & clickable on the page.
720
+ Raises NoSuchElementException if the element does not exist in the HTML
721
+ within the specified timeout.
722
+ Raises ElementNotVisibleException if the element exists in the HTML,
723
+ but is not visible (eg. opacity is "0") within the specified timeout.
724
+ Raises ElementNotInteractableException if the element is not clickable.
725
+ @Params
726
+ driver - the webdriver object (required)
727
+ selector - the locator for identifying the page element (required)
728
+ by - the type of selector being used (Default: By.CSS_SELECTOR)
729
+ timeout - the time to wait for elements in seconds
730
+ original_selector - handle pre-converted ":contains(TEXT)" selector
731
+ @Returns
732
+ A web element object
733
+ """
734
+ from selenium .webdriver .support import expected_conditions as EC
735
+ from selenium .webdriver .support .ui import WebDriverWait
736
+
737
+ element = None
738
+ is_present = False
739
+ is_visible = False
740
+ start_ms = time .time () * 1000.0
741
+ stop_ms = start_ms + (timeout * 1000.0 )
742
+ for x in range (int (timeout * 10 )):
743
+ shared_utils .check_if_time_limit_exceeded ()
744
+ try :
745
+ element = driver .find_element (by = by , value = selector )
746
+ is_present = True
747
+ if element .is_displayed ():
748
+ is_visible = True
749
+ if WebDriverWait (driver , 0.001 ).until (
750
+ EC .element_to_be_clickable ((by , selector ))
751
+ ):
752
+ return element
753
+ else :
754
+ element = None
755
+ raise Exception ()
756
+ else :
757
+ element = None
758
+ raise Exception ()
759
+ except Exception :
760
+ now_ms = time .time () * 1000.0
761
+ if now_ms >= stop_ms :
762
+ break
763
+ time .sleep (0.1 )
764
+ plural = "s"
765
+ if timeout == 1 :
766
+ plural = ""
767
+ if not element and by != By .LINK_TEXT :
768
+ if (
769
+ original_selector
770
+ and ":contains(" in original_selector
771
+ and "contains(." in selector
772
+ ):
773
+ selector = original_selector
774
+ if not is_present :
775
+ # The element does not exist in the HTML
776
+ message = "Element {%s} was not present after %s second%s!" % (
777
+ selector ,
778
+ timeout ,
779
+ plural ,
780
+ )
781
+ timeout_exception (NoSuchElementException , message )
782
+ if not is_visible :
783
+ # The element exists in the HTML, but is not visible
784
+ message = "Element {%s} was not visible after %s second%s!" % (
785
+ selector ,
786
+ timeout ,
787
+ plural ,
788
+ )
789
+ timeout_exception (ElementNotVisibleException , message )
790
+ # The element is visible in the HTML, but is not clickable
791
+ message = "Element {%s} was not clickable after %s second%s!" % (
792
+ selector ,
793
+ timeout ,
794
+ plural ,
795
+ )
796
+ timeout_exception (ElementNotInteractableException , message )
797
+ elif not element and by == By .LINK_TEXT and not is_visible :
798
+ message = "Link text {%s} was not visible after %s second%s!" % (
799
+ selector ,
800
+ timeout ,
801
+ plural ,
802
+ )
803
+ timeout_exception (ElementNotVisibleException , message )
804
+ elif not element and by == By .LINK_TEXT and is_visible :
805
+ message = "Link text {%s} was not clickable after %s second%s!" % (
806
+ selector ,
807
+ timeout ,
808
+ plural ,
809
+ )
810
+ timeout_exception (ElementNotInteractableException , message )
811
+ else :
812
+ return element
813
+
814
+
710
815
def wait_for_element_absent (
711
816
driver ,
712
817
selector ,
0 commit comments