-1

I am using Selenium with Python to automate a process to upload a file. There is an "Upload" button which is disabled by default and only becomes clickable when the file to be uploaded is chosen.

The HTML for Disabled Button is -

<button type="button" id="upload-button" data-bi-id="upload-button" class="ms-Button ms-Button--primary is-disabled root-296" disabled="" aria-label="Upload" aria-disabled="true" data-is-focusable="false">

And the HTML for button after it becomes clickable is -

<button type="button" id="upload-button" data-bi-id="upload-button" class="ms-Button ms-Button--primary root-437" aria-label="Upload" data-is-focusable="true" tabindex="0">

I am using -

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

But its not working. I believe this is clicking on the disabled button (even though the file is chosen and the button has become clickable). I also tried -

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CLASS_NAME,"ms-Button ms-Button--primary root-437"))).click()

But this gives a TimeOut Exception. So what should I do to click this button after it becomes clickable. I have tried some solutions from the Internet, but none of them seem to be working.

vitaliis
  • 4,082
  • 5
  • 18
  • 40
Anshul Verma
  • 56
  • 13

4 Answers4

1

It seems you are using wrong ID value.

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

Or use this css selector

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#upload-button[data-is-focusable='true']"))).click()
KunduK
  • 32,888
  • 5
  • 17
  • 41
  • I was initially using the correct ID value....but then I was testing a little and pasted the wrong ID here.....although I have edited it now. Also, using css selection doesnt work either.....its giving TimeOut exception. – Anshul Verma May 12 '21 at 19:34
  • CSS selector as the approach cannot be the reason of timeout exception. The reason may be wrong selector. It does not matter `css` or `xpath` – vitaliis May 13 '21 at 01:22
  • Selector suggested by Kunduk is correct. Update your questionwith more data. – vitaliis May 13 '21 at 01:36
1

Regarding the current version of your code, I think you may be right that it is clicking the button before it is really enabled. You have

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.ID,"upload-button"))).click()

You are waiting for this element to be clickable. I wanted to try and figure out exactly what this meant so I looked at the source code. element_to_be_clickable is satisfied As soon as the element is "visible" and "enabled".

Visibility, I know, is defined as presence on the DOM and height/width both > 0. From your description it sounds like your button is immediately visible. So as soon as it is "enabled", element_to_be_clickable is satisfied and the wait will end.

This begs the question, what exactly determines whether an element is "enabled"? I found that selenium's is_enabled (which is required in the source code for element_to_be_clickable to pass), is essentially a negation of the W3C specification for disabled(). What it boils down to is this single line, which states that an element is "disabled" if The element is a button, input, select, textarea, or form-associated custom element, and the disabled attribute is specified on this element (regardless of its value).

That's it. Your element does have the "disabled" attribute, but it also has some other stuff that might cause it to be disabled -- the class name contains is-disabled, it's got aria-disabled="true" as well as data-is-focusable="false", all of which change by the time the button is fully clickable. I wonder if the disabled attribute goes away before something else that also causes the element to be disabled, so just as you said maybe your click is registering before the button is ready. To debug this I would try temporarily adding a hard wait, a few seconds long, after executing the WebDriverWait and before clicking the button.

For your class name,

WebDriverWait(browser, 15).until(EC.element_to_be_clickable((By.CLASS_NAME,"ms-Button ms-Button--primary root-437"))).click()

I suspect this is a dynamic class name, the root-437 part in particular, so maybe that's why that didn't work.

Finally, are you intending to upload from your filesystem by clicking the button? Because it can only interact with your web browser and can't browse a window on your OS, that doesn't work. There's a special way to upload files--you have to identify the file input element and send the absolute path of the file you want to upload to that element using send_keys().

C. Peck
  • 3,641
  • 3
  • 19
  • 36
  • you are right about "root-437" being a dynamic class. I checked it, and it was changed to "root-437". Is this the reason why I cant click on the button? Also....about uploading the file...I have already taken care of that by using `browser.find_element(By.CSS_SELECTOR,"input[type='file']").send_keys(cwd+"\\images\\1.jpg")` So....how can I click on this button....i still dont understand – Anshul Verma May 12 '21 at 20:48
  • Good to know that the class is not dynamic, that is helpful. I didn't see that about the file upload in your first post so sorry for bringing that up. As I said above, To debug this I would try temporarily adding a hard wait, a few seconds long, after executing the `WebDriverWait` and before clicking the button. – C. Peck May 12 '21 at 21:02
  • What do you mean by hard wait?? Are you referring to Implicit Wait or time.sleep(10)?? I have tried both of these. – Anshul Verma May 12 '21 at 21:09
  • The time.sleep(10). The big piece that's missing to figure this out is that we don't have the HTML of the page or a link to it. is it possible one or more of your elements is inside an iframe? – C. Peck May 12 '21 at 21:11
  • Please try to avoid sarcasm and condescension. I understand the issue is frustrating, but there are a lot of people dedicating time to hopefully get this solved. – C. Peck May 12 '21 at 21:14
  • I'm sorry if i sounded condescending....I really wasn't trying to....idk how you got that idea.....and regarding the HTML code....I could be wrong...but i think its similar to google account's change profile picture feature. – Anshul Verma May 12 '21 at 21:17
  • No problem, misunderstandings are commonplace here. Anyway... "i think it's similar to google account's change profile picture feature"---is not going to be enough to go off of. Is your page under test public, or can you share the full HTML of the page? – C. Peck May 12 '21 at 21:20
  • @AnshulVerma I don't know if this is helpful, but I checked out the google account change profile picture feature, and all of the element for that form are inside an `iframe`. If that's the case for you, you'd have to identify and switch to that iframe before you're able to interact with elements inside the iframe. – C. Peck May 12 '21 at 21:26
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/232343/discussion-between-anshul-verma-and-c-peck). – Anshul Verma May 13 '21 at 12:14
0

As you can see, the button element while it is still disabled contains class is-disabled and contains attribute disabled and it doesn't contain these attributes when it is enabled.
So the expected condition is to locate the element defined by the following xpath:

//button[@id='upload-button' and(not(contains(@class,'is-disabled'))) and(not(@disabled))]

In other words you should use the following:

WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.XPATH, "//button[@id='upload-button' and(not(contains(@class,'is-disabled'))) and(not(@disabled))]")))

You can locate the enabled button based on absence of one of the two attributes mentioned as well.

Prophet
  • 32,350
  • 22
  • 54
  • 79
  • I tried this, but it didnt work. Although there were no errors shown. So does that mean that the presence of the Enabled Button is found? But when I tell the code to click on it....it doesnt work....the program just terminates without any errors. – Anshul Verma May 12 '21 at 20:51
  • Have you tried waiting for this element to be clickable? I mean locating it according to the absence of disabled attributes and this element to be clickable? Or visible? – Prophet May 12 '21 at 20:56
  • yeah....just did....it doesn't work – Anshul Verma May 12 '21 at 21:01
  • Really strange. It would be interesting to debug this on real web page but I can't... – Prophet May 12 '21 at 21:08
  • This might be similar to google's change profile picture option. Do you think that could help? – Anshul Verma May 12 '21 at 21:18
  • I do not understand what are you talking about? – Prophet May 12 '21 at 21:21
0

Try clicking without explicit wait, using implicit:

driver.implicitly_wait(15)
driver.find_element_by_xpath('//button[@data-is-focusable="true"]').click()

Or

driver.implicitly_wait(15)
driver.find_element_by_xpath('//button[@data-is-focusable="true" and @tabindex="0"]').click()

If this won't help, add more details to your question.

vitaliis
  • 4,082
  • 5
  • 18
  • 40