@@ -122,6 +122,17 @@ def click(self, selector, by=By.CSS_SELECTOR,
122
122
element = page_actions .wait_for_element_visible (
123
123
self .driver , selector , by , timeout = timeout )
124
124
element .click ()
125
+ except WebDriverException :
126
+ self .wait_for_ready_state_complete ()
127
+ if not by == By .LINK_TEXT :
128
+ # Only use a JavaScript click if not clicking by Link Text
129
+ self .__js_click (selector , by = by )
130
+ else :
131
+ # One more attempt to click on the element
132
+ element = page_actions .wait_for_element_visible (
133
+ self .driver , selector , by , timeout = timeout )
134
+ element .click ()
135
+
125
136
if settings .WAIT_FOR_RSC_ON_CLICKS :
126
137
self .wait_for_ready_state_complete ()
127
138
if self .demo_mode :
@@ -512,7 +523,7 @@ def update_text_value(self, selector, new_value, by=By.CSS_SELECTOR,
512
523
new_value - the new value for setting the text field
513
524
by - the type of selector to search by (Default: CSS)
514
525
timeout - how long to wait for the selector to be visible
515
- retry - if True, use jquery if the selenium text update fails
526
+ retry - if True, use JS if the selenium text update fails
516
527
"""
517
528
if self .timeout_multiplier and timeout == settings .LARGE_TIMEOUT :
518
529
timeout = self ._get_new_timeout (timeout )
@@ -556,10 +567,23 @@ def update_text_value(self, selector, new_value, by=By.CSS_SELECTOR,
556
567
element .send_keys (Keys .RETURN )
557
568
if settings .WAIT_FOR_RSC_ON_PAGE_LOADS :
558
569
self .wait_for_ready_state_complete ()
570
+ except Exception :
571
+ exc_message = self ._get_exception_message ()
572
+ update = ("Your version of ChromeDriver may be out-of-date! "
573
+ "Please go to "
574
+ "https://sites.google.com/a/chromium.org/chromedriver/ "
575
+ "and download the latest version to your system PATH! "
576
+ "Original Exception Message: %s" % exc_message )
577
+ using_old_chromedriver = False
578
+ if "unknown error: call function result missing" in exc_message :
579
+ using_old_chromedriver = True
580
+ if self .browser == 'chrome' and using_old_chromedriver :
581
+ raise Exception (update )
582
+ else :
583
+ raise Exception (exc_message )
559
584
if (retry and element .get_attribute ('value' ) != new_value and (
560
585
not new_value .endswith ('\n ' ))):
561
- logging .debug ('update_text_value is falling back to jQuery!' )
562
- selector = re .escape (selector )
586
+ logging .debug ('update_text() is falling back to JavaScript!' )
563
587
self .set_value (selector , new_value , by = by )
564
588
if self .demo_mode :
565
589
if self .driver .current_url != pre_action_url :
@@ -772,7 +796,7 @@ def bring_to_front(self, selector, by=By.CSS_SELECTOR):
772
796
773
797
def highlight (self , selector , by = By .CSS_SELECTOR ,
774
798
loops = settings .HIGHLIGHTS , scroll = True ):
775
- """ This method uses fancy javascript to highlight an element.
799
+ """ This method uses fancy JavaScript to highlight an element.
776
800
Used during demo_mode.
777
801
@Params
778
802
selector - the selector of the element to find
@@ -930,13 +954,37 @@ def scroll_click(self, selector, by=By.CSS_SELECTOR):
930
954
def click_xpath (self , xpath ):
931
955
self .click (xpath , by = By .XPATH )
932
956
957
+ def js_click (self , selector , by = By .CSS_SELECTOR ):
958
+ """ Clicks an element using pure JS. Does not use jQuery. """
959
+ selector , by = self ._recalculate_selector (selector , by )
960
+ if by == By .LINK_TEXT :
961
+ message = (
962
+ "Pure JavaScript doesn't support clicking by Link Text. "
963
+ "You may want to use self.jquery_click() instead, which "
964
+ "allows this with :contains(), assuming jQuery isn't blocked. "
965
+ "For now, self.js_click() will use a regular WebDriver click." )
966
+ logging .debug (message )
967
+ self .click (selector , by = by )
968
+ return
969
+ element = self .wait_for_element_present (
970
+ selector , by = by , timeout = settings .SMALL_TIMEOUT )
971
+ if self .is_element_visible (selector , by = by ):
972
+ self ._demo_mode_highlight_if_active (selector , by )
973
+ if not self .demo_mode :
974
+ self ._scroll_to_element (element )
975
+ css_selector = self .convert_to_css_selector (selector , by = by )
976
+ css_selector = re .escape (css_selector )
977
+ self .__js_click (selector , by = by ) # The real "magic" happens here
978
+ self ._demo_mode_pause_if_active ()
979
+
933
980
def jquery_click (self , selector , by = By .CSS_SELECTOR ):
981
+ """ Clicks an element using jQuery. Different from using pure JS. """
934
982
selector , by = self ._recalculate_selector (selector , by )
935
- selector = self .convert_to_css_selector (selector , by = by )
936
983
self .wait_for_element_present (
937
984
selector , by = by , timeout = settings .SMALL_TIMEOUT )
938
985
if self .is_element_visible (selector , by = by ):
939
986
self ._demo_mode_highlight_if_active (selector , by )
987
+ selector = self .convert_to_css_selector (selector , by = by )
940
988
selector = self ._make_css_match_first_element_only (selector )
941
989
click_script = """jQuery('%s')[0].click()""" % selector
942
990
self .safe_execute_script (click_script )
@@ -1056,7 +1104,8 @@ def convert_xpath_to_css(self, xpath):
1056
1104
def convert_to_css_selector (self , selector , by ):
1057
1105
""" This method converts a selector to a CSS_SELECTOR.
1058
1106
jQuery commands require a CSS_SELECTOR for finding elements.
1059
- This method should only be used for jQuery actions. """
1107
+ This method should only be used for jQuery/JavaScript actions.
1108
+ Pure JavaScript doesn't support using a:contains("LINK_TEXT"). """
1060
1109
if by == By .CSS_SELECTOR :
1061
1110
return selector
1062
1111
elif by == By .ID :
@@ -1080,21 +1129,21 @@ def convert_to_css_selector(self, selector, by):
1080
1129
1081
1130
def set_value (self , selector , new_value , by = By .CSS_SELECTOR ,
1082
1131
timeout = settings .LARGE_TIMEOUT ):
1083
- """ This method uses jQuery to update a text field.
1084
- Similar to jquery_update_text_value(), but the element
1085
- doesn't need to be officially visible to work. """
1132
+ """ This method uses JavaScript to update a text field. """
1086
1133
if self .timeout_multiplier and timeout == settings .LARGE_TIMEOUT :
1087
1134
timeout = self ._get_new_timeout (timeout )
1088
1135
if page_utils .is_xpath_selector (selector ):
1089
1136
by = By .XPATH
1090
1137
orginal_selector = selector
1091
- selector = self .convert_to_css_selector (selector , by = by )
1092
- self ._demo_mode_highlight_if_active (selector , by )
1093
- self .scroll_to (selector , by = by , timeout = timeout )
1094
- value = json .dumps (new_value )
1095
- selector = self ._make_css_match_first_element_only (selector )
1096
- set_value_script = """jQuery('%s').val(%s)""" % (selector , value )
1097
- self .safe_execute_script (set_value_script )
1138
+ css_selector = self .convert_to_css_selector (selector , by = by )
1139
+ self ._demo_mode_highlight_if_active (orginal_selector , by )
1140
+ if not self .demo_mode :
1141
+ self .scroll_to (orginal_selector , by = by , timeout = timeout )
1142
+ value = re .escape (new_value )
1143
+ css_selector = re .escape (css_selector )
1144
+ script = ("""document.querySelector('%s').value='%s';"""
1145
+ % (css_selector , value ))
1146
+ self .execute_script (script )
1098
1147
if new_value .endswith ('\n ' ):
1099
1148
element = self .wait_for_element_present (
1100
1149
orginal_selector , by = by , timeout = timeout )
@@ -1103,12 +1152,20 @@ def set_value(self, selector, new_value, by=By.CSS_SELECTOR,
1103
1152
self .wait_for_ready_state_complete ()
1104
1153
self ._demo_mode_pause_if_active ()
1105
1154
1155
+ def js_update_text (self , selector , new_value , by = By .CSS_SELECTOR ,
1156
+ timeout = settings .LARGE_TIMEOUT ):
1157
+ """ Same as self.set_value() """
1158
+ if self .timeout_multiplier and timeout == settings .LARGE_TIMEOUT :
1159
+ timeout = self ._get_new_timeout (timeout )
1160
+ self .set_value (
1161
+ selector , new_value , by = by , timeout = timeout )
1162
+
1106
1163
def jquery_update_text_value (self , selector , new_value , by = By .CSS_SELECTOR ,
1107
1164
timeout = settings .LARGE_TIMEOUT ):
1108
1165
""" This method uses jQuery to update a text field.
1109
1166
If the new_value string ends with the newline character,
1110
1167
WebDriver will finish the call, which simulates pressing
1111
- {Enter/Return} after the text is entered. """
1168
+ {Enter/Return} after the text is entered. """
1112
1169
if self .timeout_multiplier and timeout == settings .LARGE_TIMEOUT :
1113
1170
timeout = self ._get_new_timeout (timeout )
1114
1171
if page_utils .is_xpath_selector (selector ):
@@ -1128,7 +1185,7 @@ def jquery_update_text_value(self, selector, new_value, by=By.CSS_SELECTOR,
1128
1185
1129
1186
def jquery_update_text (self , selector , new_value , by = By .CSS_SELECTOR ,
1130
1187
timeout = settings .LARGE_TIMEOUT ):
1131
- """ The shorter version of jquery_update_text_value()
1188
+ """ The shorter version of self. jquery_update_text_value()
1132
1189
(The longer version remains for backwards compatibility.) """
1133
1190
if self .timeout_multiplier and timeout == settings .LARGE_TIMEOUT :
1134
1191
timeout = self ._get_new_timeout (timeout )
@@ -1740,6 +1797,24 @@ def process_checks(self, print_only=False):
1740
1797
1741
1798
############
1742
1799
1800
+ def __js_click (self , selector , by = By .CSS_SELECTOR ):
1801
+ """ Clicks an element using pure JS. Does not use jQuery. """
1802
+ selector , by = self ._recalculate_selector (selector , by )
1803
+ css_selector = self .convert_to_css_selector (selector , by = by )
1804
+ css_selector = re .escape (css_selector )
1805
+ script = ("""var simulateClick = function (elem) {
1806
+ var evt = new MouseEvent('click', {
1807
+ bubbles: true,
1808
+ cancelable: true,
1809
+ view: window
1810
+ });
1811
+ var canceled = !elem.dispatchEvent(evt);
1812
+ };
1813
+ var someLink = document.querySelector('%s');
1814
+ simulateClick(someLink);"""
1815
+ % css_selector )
1816
+ self .execute_script (script )
1817
+
1743
1818
def _get_href_from_link_text (self , link_text , hard_fail = True ):
1744
1819
href = self .get_link_attribute (link_text , "href" , hard_fail )
1745
1820
if not href :
0 commit comments