Skip to content

Commit a23f7eb

Browse files
committed
Handle clicking link text hidden in a dropdown menu.
1 parent c0d73e0 commit a23f7eb

File tree

1 file changed

+105
-29
lines changed

1 file changed

+105
-29
lines changed

seleniumbase/fixtures/base_case.py

Lines changed: 105 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ def click(self, selector, by=By.CSS_SELECTOR,
9494
timeout = self._get_new_timeout(timeout)
9595
if page_utils.is_xpath_selector(selector):
9696
by = By.XPATH
97+
if page_utils.is_link_text_selector(selector):
98+
selector = page_utils.get_link_text_from_selector(selector)
99+
by = By.LINK_TEXT
100+
if not self.is_link_text_visible(selector):
101+
# Handle a special case of links hidden in dropdowns
102+
self.click_link_text(selector, timeout=timeout)
103+
return
97104
element = page_actions.wait_for_element_visible(
98105
self.driver, selector, by, timeout=timeout)
99106
self._demo_mode_highlight_if_active(selector, by)
@@ -161,6 +168,59 @@ def click_chain(self, selectors_list, by=By.CSS_SELECTOR,
161168
if spacing > 0:
162169
time.sleep(spacing)
163170

171+
def is_link_text_present(self, link_text):
172+
""" Returns True if the link text appears in the HTML of the page.
173+
The element doesn't need to be visible,
174+
such as elements hidden inside a dropdown selection. """
175+
self.wait_for_ready_state_complete()
176+
source = self.driver.page_source
177+
soup = BeautifulSoup(source, "html.parser")
178+
html_links = soup.find_all('a')
179+
for html_link in html_links:
180+
if html_link.text == link_text:
181+
if html_link.has_attr('href'):
182+
return True
183+
return False
184+
185+
def get_href_from_link_text(self, link_text):
186+
self.wait_for_ready_state_complete()
187+
source = self.driver.page_source
188+
soup = BeautifulSoup(source, "html.parser")
189+
html_links = soup.find_all('a')
190+
for html_link in html_links:
191+
if html_link.text == link_text:
192+
if html_link.has_attr('href'):
193+
href = html_link.get('href')
194+
if href.startswith('//'):
195+
link = "http:" + href
196+
elif href.startswith('/'):
197+
url = self.driver.current_url
198+
domain_url = self.get_domain_url(url)
199+
link = domain_url + href
200+
else:
201+
link = href
202+
return link
203+
raise Exception(
204+
'Could not parse link from link_text [%s]' % link_text)
205+
raise Exception("Link Text [%s] was not found!" % link_text)
206+
207+
def wait_for_href_from_link_text(self, link_text,
208+
timeout=settings.SMALL_TIMEOUT):
209+
start_ms = time.time() * 1000.0
210+
stop_ms = start_ms + (timeout * 1000.0)
211+
for x in range(int(timeout * 5)):
212+
try:
213+
href = self.get_href_from_link_text(link_text)
214+
return href
215+
except Exception:
216+
now_ms = time.time() * 1000.0
217+
if now_ms >= stop_ms:
218+
break
219+
time.sleep(0.2)
220+
raise Exception(
221+
"Link text [%s] was not present after %s seconds!" % (
222+
link_text, timeout))
223+
164224
def click_link_text(self, link_text, timeout=settings.SMALL_TIMEOUT):
165225
""" This method clicks link text on a page """
166226
# If using phantomjs, might need to extract and open the link directly
@@ -171,38 +231,28 @@ def click_link_text(self, link_text, timeout=settings.SMALL_TIMEOUT):
171231
element = self.wait_for_link_text_visible(link_text)
172232
element.click()
173233
return
174-
source = self.driver.page_source
175-
soup = BeautifulSoup(source, "html.parser")
176-
html_links = soup.find_all('a')
177-
for html_link in html_links:
178-
if html_link.text == link_text:
179-
if html_link.has_attr('href'):
180-
href = html_link.get('href')
181-
if href.startswith('//'):
182-
link = "http:" + href
183-
elif href.startswith('/'):
184-
url = self.driver.current_url
185-
domain_url = self.get_domain_url(url)
186-
link = domain_url + href
187-
else:
188-
link = href
189-
self.open(link)
190-
return
191-
raise Exception(
192-
'Could not parse link from link_text [%s]' % link_text)
193-
raise Exception("Link text [%s] was not found!" % link_text)
194-
# Not using phantomjs
195-
element = self.wait_for_link_text_visible(link_text, timeout=timeout)
196-
self._demo_mode_highlight_if_active(link_text, by=By.LINK_TEXT)
234+
self.open(self.get_href_from_link_text(link_text))
235+
return
236+
self.wait_for_href_from_link_text(link_text, timeout=timeout)
197237
pre_action_url = self.driver.current_url
198238
try:
199-
element.click()
200-
except (StaleElementReferenceException, ENI_Exception):
201-
self.wait_for_ready_state_complete()
202-
time.sleep(0.05)
203239
element = self.wait_for_link_text_visible(
204-
link_text, timeout=timeout)
205-
element.click()
240+
link_text, timeout=0.2)
241+
self._demo_mode_highlight_if_active(link_text, by=By.LINK_TEXT)
242+
try:
243+
element.click()
244+
except (StaleElementReferenceException, ENI_Exception):
245+
self.wait_for_ready_state_complete()
246+
time.sleep(0.05)
247+
element = self.wait_for_link_text_visible(
248+
link_text, timeout=timeout)
249+
element.click()
250+
except Exception:
251+
# The link text is probably hidden under a dropdown menu
252+
if not self._click_dropdown_link_text(link_text):
253+
element = self.wait_for_link_text_visible(
254+
link_text, timeout=settings.MINI_TIMEOUT)
255+
element.click()
206256
if settings.WAIT_FOR_RSC_ON_CLICKS:
207257
self.wait_for_ready_state_complete()
208258
if self.demo_mode:
@@ -1283,6 +1333,32 @@ def process_checks(self, print_only=False):
12831333

12841334
############
12851335

1336+
def _click_dropdown_link_text(self, link_text):
1337+
""" When a link is hidden under a dropdown menu, use this. """
1338+
href = self.wait_for_href_from_link_text(link_text)
1339+
source = self.driver.page_source
1340+
soup = BeautifulSoup(source, "html.parser")
1341+
drop_down_list = soup.select('[class*=dropdown]')
1342+
for item in drop_down_list:
1343+
if link_text in item.text.split('\n') and href in item.decode():
1344+
dropdown_css = ""
1345+
for css_class in item['class']:
1346+
dropdown_css += '.'
1347+
dropdown_css += css_class
1348+
dropdown_css = item.name + dropdown_css
1349+
link_css = '[href="%s"]' % href
1350+
matching_dropdowns = self.find_visible_elements(dropdown_css)
1351+
for dropdown in matching_dropdowns:
1352+
# The same class names might be used for multiple dropdowns
1353+
try:
1354+
page_actions.hover_element_and_click(
1355+
self.driver, dropdown, link_css,
1356+
click_by=By.CSS_SELECTOR, timeout=0.2)
1357+
return True
1358+
except Exception:
1359+
pass
1360+
return False
1361+
12861362
def _pick_select_option(self, dropdown_selector, option,
12871363
dropdown_by=By.CSS_SELECTOR, option_by="text",
12881364
timeout=settings.SMALL_TIMEOUT):

0 commit comments

Comments
 (0)