balkon16
balkon16

Reputation: 1448

Python Selenium click the button once a drop-down menu is available

There is an 'Export drop down menu button' that can be either active:

enter image description here

<a id="ctl32_ctl05_ctl04_ctl00_ButtonLink" title="Export drop down menu" alt="Export drop down menu" href="javascript:void(0)" style="text-decoration: none; cursor: pointer;">
    <img id="ctl32_ctl05_ctl04_ctl00_ButtonImg" src="/Reports/Reserved.ReportViewerWebControl.axd?OpType=Resource&amp;Version=11.0.7001.0&amp;Name=Microsoft.Reporting.WebForms.Icons.Export.gif" alt="Export drop down menu" style="border-style:None;height:16px;width:16px;border-width:0px;">
    <span style="width:5px;text-decoration:none;"> </span>
    <img id="ctl32_ctl05_ctl04_ctl00_ButtonImgDown" src="/Reports/Reserved.ReportViewerWebControl.axd?OpType=Resource&amp;Version=11.0.7001.0&amp;Name=Microsoft.Reporting.WebForms.Icons.ArrowDown.gif" alt="Export drop down menu" style="border-style:None;height:6px;width:7px;border-width:0px;margin-bottom:5px;">
</a>

or inactive:

enter image description here

<a id="ctl32_ctl05_ctl04_ctl00_ButtonLink" title="Export drop down menu" alt="Export drop down menu" href="javascript:void(0)" style="text-decoration: none; cursor: default;">
    <img id="ctl32_ctl05_ctl04_ctl00_ButtonImg" src="/Reports/Reserved.ReportViewerWebControl.axd?OpType=Resource&amp;Version=11.0.7001.0&amp;Name=Microsoft.Reporting.WebForms.Icons.ExportDisabled.gif" alt="Export drop down menu" style="border-style:None;height:16px;width:16px;border-width:0px;">
    <span style="width:5px;text-decoration:none;"> </span>
    <img id="ctl32_ctl05_ctl04_ctl00_ButtonImgDown" src="/Reports/Reserved.ReportViewerWebControl.axd?OpType=Resource&amp;Version=11.0.7001.0&amp;Name=Microsoft.Reporting.WebForms.Icons.ArrowDownDisabled.gif" alt="Export drop down menu" style="border-style:None;height:6px;width:7px;border-width:0px;margin-bottom:5px;">
</a>

If you click on the button when it's active you get a drop-down menu:

enter image description here

Waiting time until the button is active can vary greatly (from few seconds up to few minutes). In the end I need to click one of the options in the drop-down menu but I can't get there until the button is active and clickable1.

My current implementation is:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ... 
wait_long = WebDriverWait(chrome_driver, 360)
export_button = wait_long.until(EC.element_to_be_clickable((By.XPATH, '//*[@title="Export drop down menu"]')))
export_button.click()

wait_5 = WebDriverWait(chrome_driver, 5)
csv_button = wait_5 .until(EC.visibility_of_element_located((By.XPATH, '//*[@title="CSV (comma delimited)"]')))
csv_button.click()

The problem with this implementation is that the button is clickable right away so the export_button is clicked instantaneously but since it's inactive the drop-down menu doesn't show up. Is there a way for chrome_driver to wait until the button is truly clickable?

I noticed that both states of the button are represented with different files: Export.gif for active and ExportDisabled.gif for inactive. It may be possible to write a custom wait condition (https://selenium-python.readthedocs.io/waits.html#explicit-waits) but I find it hardly an elegant solution. Is there a way to implement the behavior I want in another (simpler) way?

1 According to Selenium's behavior I've observed, the button is clickable at all times. The only difference between it being active and inactive is the fact the in the latter the drop-down menu doesn't show up once the button is clicked.

Upvotes: 0

Views: 557

Answers (1)

JeffC
JeffC

Reputation: 25645

Without the HTML, it's impossible to give you an actual locator that will work on your site but I'll make one up that I'm guessing should be close and hopefully point you in the right direction.

Here's my mock HTML:

<a href="...">
    <img src="../Export.gif">
</a>

Given that HTML, we can write a CSS selector

a > img[src$='Export.gif']

Now you can use it in your WebDriverWait

export_button = wait_long.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a > img[src$='Export.gif']")))

Now this line will wait until the icon is enabled, based on the gif, and then you can click it.

NOTE: Post the HTML of the icon in a disabled and enabled state and message me and I'll come back and update it to the real HTML.


Now that the actual HTML is posted, the mock HTML was correct and the locator would actually work. I might make one minor tweak to make it more specific but it's probably not necessary.

a[title="Export drop down menu"] > img[src$="Export.gif"]

You can try both/either and see.

Upvotes: 1

Related Questions