@@ -109,12 +109,13 @@ def click(self, selector, by=By.CSS_SELECTOR,
109109 if self .timeout_multiplier and timeout == settings .SMALL_TIMEOUT :
110110 timeout = self .__get_new_timeout (timeout )
111111 selector , by = self .__recalculate_selector (selector , by )
112- if page_utils .is_link_text_selector (selector ):
112+ if page_utils .is_link_text_selector (selector ) or by == By . LINK_TEXT :
113113 if not self .is_link_text_visible (selector ):
114114 # Handle a special case of links hidden in dropdowns
115115 self .click_link_text (selector , timeout = timeout )
116116 return
117- if page_utils .is_partial_link_text_selector (selector ):
117+ if page_utils .is_partial_link_text_selector (selector ) or (
118+ by == By .PARTIAL_LINK_TEXT ):
118119 if not self .is_partial_link_text_visible (selector ):
119120 # Handle a special case of partial links hidden in dropdowns
120121 self .click_partial_link_text (selector , timeout = timeout )
@@ -232,6 +233,17 @@ def is_link_text_present(self, link_text):
232233 return True
233234 return False
234235
236+ def is_partial_link_text_present (self , link_text ):
237+ """ Returns True if the partial link appears in the HTML of the page.
238+ The element doesn't need to be visible,
239+ such as elements hidden inside a dropdown selection. """
240+ soup = self .get_beautiful_soup ()
241+ html_links = soup .find_all ('a' )
242+ for html_link in html_links :
243+ if link_text .strip () in html_link .text .strip ():
244+ return True
245+ return False
246+
235247 def get_link_attribute (self , link_text , attribute , hard_fail = True ):
236248 """ Finds a link by link text and then returns the attribute's value.
237249 If the link text or attribute cannot be found, an exception will
@@ -254,6 +266,31 @@ def get_link_attribute(self, link_text, attribute, hard_fail=True):
254266 else :
255267 return None
256268
269+ def get_partial_link_attribute (self , link_text , attribute , hard_fail = True ):
270+ """ Finds a link by partial link text and then returns the attribute's
271+ value. If the partial link text or attribute cannot be found, an
272+ exception will get raised if hard_fail is True (otherwise None
273+ is returned). """
274+ soup = self .get_beautiful_soup ()
275+ html_links = soup .find_all ('a' )
276+ for html_link in html_links :
277+ if link_text .strip () in html_link .text .strip ():
278+ if html_link .has_attr (attribute ):
279+ attribute_value = html_link .get (attribute )
280+ return attribute_value
281+ if hard_fail :
282+ raise Exception (
283+ 'Unable to find attribute {%s} from '
284+ 'partial link text {%s}!'
285+ % (attribute , link_text ))
286+ else :
287+ return None
288+ if hard_fail :
289+ raise Exception (
290+ "Partial Link text {%s} was not found!" % link_text )
291+ else :
292+ return None
293+
257294 def wait_for_link_text_present (self , link_text ,
258295 timeout = settings .SMALL_TIMEOUT ):
259296 start_ms = time .time () * 1000.0
@@ -273,6 +310,25 @@ def wait_for_link_text_present(self, link_text,
273310 "Link text {%s} was not present after %s seconds!" % (
274311 link_text , timeout ))
275312
313+ def wait_for_partial_link_text_present (self , link_text ,
314+ timeout = settings .SMALL_TIMEOUT ):
315+ start_ms = time .time () * 1000.0
316+ stop_ms = start_ms + (timeout * 1000.0 )
317+ for x in range (int (timeout * 5 )):
318+ try :
319+ if not self .is_partial_link_text_present (link_text ):
320+ raise Exception (
321+ "Partial Link text {%s} was not found!" % link_text )
322+ return
323+ except Exception :
324+ now_ms = time .time () * 1000.0
325+ if now_ms >= stop_ms :
326+ break
327+ time .sleep (0.2 )
328+ raise Exception (
329+ "Partial Link text {%s} was not present after %s seconds!" % (
330+ link_text , timeout ))
331+
276332 def click_link_text (self , link_text , timeout = settings .SMALL_TIMEOUT ):
277333 """ This method clicks link text on a page """
278334 # If using phantomjs, might need to extract and open the link directly
@@ -387,20 +443,68 @@ def click_partial_link_text(self, partial_link_text,
387443 '{%s}' % partial_link_text )
388444 raise Exception (
389445 "Partial link text {%s} was not found!" % partial_link_text )
390- # Not using phantomjs
391- element = self .wait_for_partial_link_text (
392- partial_link_text , timeout = timeout )
393- self .__demo_mode_highlight_if_active (
394- partial_link_text , by = By .PARTIAL_LINK_TEXT )
395- pre_action_url = self .driver .current_url
446+ if not self .is_partial_link_text_present (partial_link_text ):
447+ self .wait_for_partial_link_text_present (
448+ partial_link_text , timeout = timeout )
449+ pre_action_url = self .get_current_url ()
396450 try :
397- element .click ()
398- except (StaleElementReferenceException , ENI_Exception ):
399- self .wait_for_ready_state_complete ()
400- time .sleep (0.05 )
401451 element = self .wait_for_partial_link_text (
402- partial_link_text , timeout = timeout )
403- element .click ()
452+ partial_link_text , timeout = 0.2 )
453+ self .__demo_mode_highlight_if_active (
454+ partial_link_text , by = By .LINK_TEXT )
455+ try :
456+ element .click ()
457+ except (StaleElementReferenceException , ENI_Exception ):
458+ self .wait_for_ready_state_complete ()
459+ time .sleep (0.05 )
460+ element = self .wait_for_partial_link_text (
461+ partial_link_text , timeout = timeout )
462+ element .click ()
463+ except Exception :
464+ found_css = False
465+ text_id = self .get_partial_link_attribute (
466+ partial_link_text , "id" , False )
467+ if text_id :
468+ link_css = '[id="%s"]' % partial_link_text
469+ found_css = True
470+
471+ if not found_css :
472+ href = self .__get_href_from_partial_link_text (
473+ partial_link_text , False )
474+ if href :
475+ if href .startswith ('/' ) or page_utils .is_valid_url (href ):
476+ link_css = '[href="%s"]' % href
477+ found_css = True
478+
479+ if not found_css :
480+ ngclick = self .get_partial_link_attribute (
481+ partial_link_text , "ng-click" , False )
482+ if ngclick :
483+ link_css = '[ng-click="%s"]' % ngclick
484+ found_css = True
485+
486+ if not found_css :
487+ onclick = self .get_partial_link_attribute (
488+ partial_link_text , "onclick" , False )
489+ if onclick :
490+ link_css = '[onclick="%s"]' % onclick
491+ found_css = True
492+
493+ success = False
494+ if found_css :
495+ if self .is_element_visible (link_css ):
496+ self .click (link_css )
497+ success = True
498+ else :
499+ # The link text might be hidden under a dropdown menu
500+ success = self .__click_dropdown_partial_link_text (
501+ partial_link_text , link_css )
502+
503+ if not success :
504+ element = self .wait_for_link_text_visible (
505+ partial_link_text , timeout = settings .MINI_TIMEOUT )
506+ element .click ()
507+
404508 if settings .WAIT_FOR_RSC_ON_CLICKS :
405509 self .wait_for_ready_state_complete ()
406510 if self .demo_mode :
@@ -3064,29 +3168,75 @@ def __get_href_from_link_text(self, link_text, hard_fail=True):
30643168 def __click_dropdown_link_text (self , link_text , link_css ):
30653169 """ When a link may be hidden under a dropdown menu, use this. """
30663170 soup = self .get_beautiful_soup ()
3067- drop_down_list = soup .select ('[class*=dropdown]' )
3068- for item in soup .select ('[class*=HeaderMenu]' ):
3069- drop_down_list .append (item )
3070- for item in soup .select ('[class*=menu-item]' ):
3171+ drop_down_list = []
3172+ for item in soup .select ('li[class]' ):
30713173 drop_down_list .append (item )
3072- for item in soup .select ('[class*=chevron]' ):
3174+ csstype = link_css .split ('[' )[1 ].split ('=' )[0 ]
3175+ for item in drop_down_list :
3176+ item_text_list = item .text .split ('\n ' )
3177+ if link_text in item_text_list and csstype in item .decode ():
3178+ dropdown_css = ""
3179+ try :
3180+ for css_class in item ['class' ]:
3181+ dropdown_css += '.'
3182+ dropdown_css += css_class
3183+ except Exception :
3184+ continue
3185+ dropdown_css = item .name + dropdown_css
3186+ matching_dropdowns = self .find_visible_elements (dropdown_css )
3187+ for dropdown in matching_dropdowns :
3188+ # The same class names might be used for multiple dropdowns
3189+ try :
3190+ if dropdown .is_displayed ():
3191+ page_actions .hover_element_and_click (
3192+ self .driver , dropdown , link_text ,
3193+ click_by = By .LINK_TEXT , timeout = 0.12 )
3194+ return True
3195+ except Exception :
3196+ pass
3197+ return False
3198+
3199+ def __get_href_from_partial_link_text (self , link_text , hard_fail = True ):
3200+ href = self .get_partial_link_attribute (link_text , "href" , hard_fail )
3201+ if not href :
3202+ return None
3203+ if href .startswith ('//' ):
3204+ link = "http:" + href
3205+ elif href .startswith ('/' ):
3206+ url = self .driver .current_url
3207+ domain_url = self .get_domain_url (url )
3208+ link = domain_url + href
3209+ else :
3210+ link = href
3211+ return link
3212+
3213+ def __click_dropdown_partial_link_text (self , link_text , link_css ):
3214+ """ When a partial link may be hidden under a dropdown, use this. """
3215+ soup = self .get_beautiful_soup ()
3216+ drop_down_list = []
3217+ for item in soup .select ('li[class]' ):
30733218 drop_down_list .append (item )
30743219 csstype = link_css .split ('[' )[1 ].split ('=' )[0 ]
30753220 for item in drop_down_list :
3076- if link_text in item .text .split ('\n ' ) and csstype in item .decode ():
3221+ item_text_list = item .text .split ('\n ' )
3222+ if link_text in item_text_list and csstype in item .decode ():
30773223 dropdown_css = ""
3078- for css_class in item ['class' ]:
3079- dropdown_css += '.'
3080- dropdown_css += css_class
3224+ try :
3225+ for css_class in item ['class' ]:
3226+ dropdown_css += '.'
3227+ dropdown_css += css_class
3228+ except Exception :
3229+ continue
30813230 dropdown_css = item .name + dropdown_css
30823231 matching_dropdowns = self .find_visible_elements (dropdown_css )
30833232 for dropdown in matching_dropdowns :
30843233 # The same class names might be used for multiple dropdowns
30853234 try :
3086- page_actions .hover_element_and_click (
3087- self .driver , dropdown , link_text ,
3088- click_by = By .LINK_TEXT , timeout = 0.2 )
3089- return True
3235+ if dropdown .is_displayed ():
3236+ page_actions .hover_element_and_click (
3237+ self .driver , dropdown , link_text ,
3238+ click_by = By .PARTIAL_LINK_TEXT , timeout = 0.12 )
3239+ return True
30903240 except Exception :
30913241 pass
30923242 return False
0 commit comments