2

I am trying to click a button with Selenium, but keeps returning that the element is not interactable. I tried maximazing the window, explicit waits, but the program simple exits after the waiting time.

<div class="actions-toolbar">
:: before
            <div class="primary">
                <button class="action primary checkout" type="submit" data-bind="
                        click: placeOrder,
                        attr: {title: $t('Place Order')},
                        css: {disabled: !isPlaceOrderActionAllowed()},
                        enable: (getCode() == isChecked())
                        " title="Go to payment">
                    <span data-bind="i18n: 'Place Order'">Go to payment</span>
                </button>
            </div>
::after
        </div>

This is what I have coding:

download_button_path = "//div[@class='actions-toolbar']/div[@class='primary']/button[1]"
button_to_click = driver.find_element(By.XPATH, download_button_path)
hover = ActionChains(driver).move_to_element(button_to_click)
hover.perform()
button_to_click.click()
sound wave
  • 3,191
  • 3
  • 11
  • 29
flolivei
  • 23
  • 4
  • Update the question with the text based HTML and your code trials. – undetected Selenium Feb 24 '23 at 21:06
  • try two things. Give the button an id and then find the element by id instead of by xpath. another thing you can try is implementing a wait command after the find element line. That sometimes gives the browser enough time to parse the html to find it. Using the id is a trick to find it quicker without a wait. – JustBeingHelpful Feb 24 '23 at 21:16
  • @MacGyver How exactly do you expect him to "Give the button an id"? Having an ID doesn't make it any faster... unless you think a few ms faster is noticeably faster. – JeffC Feb 25 '23 at 05:43
  • Why are you trying to hover the button to click it? Can you post a link to the page? – JeffC Feb 25 '23 at 05:44
  • @JeffC when the Selenium API assigns an element data to the element variable, this takes time--somewhere in the miliseconds (which is why the wait command uses that as units). I'm not sure of the inner workings of Selenium, but I wrote Selenium WebDriver tests for a job for two years, and this was the solution if the element/tag didn't have an explicit id. – JustBeingHelpful Feb 25 '23 at 06:10
  • In this example, the variable is button_to_click in this context. Typically Selenium WebDriver tests are written at a software company or a company that writes software in house. If both the web page (dynamic source code) is written in house, then the person writing the Selenium tests would simply ask that software developer or web developer to add ids and then write new tests. This makes testing easier and faster (in terms of performance) – JustBeingHelpful Feb 25 '23 at 06:11
  • @MacGyver `when the Selenium API assigns an element data to the element variable, this takes time` This takes the same amount of time whether the element is located by ID or XPath or whatever locator type. What we're talking about is the time it takes the browser to locate an element based on the different locator types. A CSS selector (which is what most drivers convert By.ID to) vs a (reasonably written) XPath is on the order of a few ms difference. OP said he tried explicit waits so asking the dev to put an ID on an element isn't going to help here. – JeffC Feb 25 '23 at 06:20
  • Also, 9 out of 10 people asking questions on SO aren't writing tests against websites for work so they don't have the option to ask for an ID to be added. Either way... none of this is related to the question. The element is being found, OP is just getting an exception that the element isn't interactable so it's not an ID vs XPath or even likely a timing issue. – JeffC Feb 25 '23 at 06:21
  • @JeffC thanks. I didn't see he wrote "explicit waits". Another thing to try is to work backwards with the code by making the code simple and try adding things in slowly on each try. Or the reverse. In other words, grab the html source code of the web page and make it a static page of your own instead of connecting to the actual web page. Most html are rendered from dynamic source code. Try different tests using the static html. If you can make it work there, it could be a timing issue with a script on the page. – JustBeingHelpful Feb 25 '23 at 07:16
  • The data bind might be causing something strange. Try removing that on the static html page and do your test and see if it works. – JustBeingHelpful Feb 25 '23 at 07:20
  • Hello, thank you all for the feedback. I am trying to automate manual actions on a website (not owned by me) so changing the source web code it's not really an option. I am afraid the css in the button might be enabling/disabling it as I see in the webpage source code. The hovering was also a tentative solution I saw in some other post but it's also not solving the problem. I am really stuck here. – flolivei Feb 25 '23 at 23:27
  • @flolivei, yes, you can change the html source code. In the browser, go to the html source and copy the html into a text file and name it test.html in a local directory. Also find any css reference files and when you save the html file, make sure to change the path of the css files. Then run your Selenium test against that static html file under localhost. This way you CAN change the html code to confirm. – JustBeingHelpful Feb 26 '23 at 03:23
  • https://stackoverflow.com/questions/23343191/copying-html-code-in-google-chromes-inspect-element – JustBeingHelpful Feb 26 '23 at 03:25
  • run local web page in Linux as localhost: https://stackoverflow.com/questions/38497334/how-to-run-html-file-on-localhost – JustBeingHelpful Feb 26 '23 at 03:34
  • run local web page in Windows as localhost: https://voices.uchicago.edu/dkchristensen/2019/01/28/local-host-for-windows/ – JustBeingHelpful Feb 26 '23 at 03:35
  • Rule of thumb for programming: if you have all of the source code for a program, you can solve anything. If you do not have all of the source code for a program, you can attempt to solve anything if you have a call stack, but it's a guessing game. Always aim for the former. In this case, the way to do that is to copy what you can see as rendered HTML into your own web page on your own web server (localhost) and work with that. It's the best you can do. Good luck my friend! – JustBeingHelpful Feb 26 '23 at 03:41
  • can you share url of the website? there are lot of ways to click a button – sound wave Feb 28 '23 at 19:50
  • Hi @soundwave the webpage of this specific button is only accessible after login and a few steps. I did copy the source code and removed some personal data -> https://1drv.ms/u/s!AgLQMXnYgt57o2xjjhp767keGsVO?e=RfyjDP my issue is with the button "GO TO PAYMENT" and I am really struggling with this :/ – flolivei Mar 01 '23 at 21:31
  • also @MacGyver thank you very much for the suggestions I appreciate it. I did what you recommended, running it locally and removing the data bind, but still selenium returns the same message. – flolivei Mar 01 '23 at 22:32
  • Are you sure the perform and click are in the correct order and with the correct objects? See this. https://sqa.stackexchange.com/questions/27529/selenium-python-action-move-to-doesnt-work-on-hover-element – JustBeingHelpful Mar 02 '23 at 05:04
  • This example also has them reversed from the order you have them being used. Also, which specific line did the code fail on? On the move_to_element, on the perform or on the click? https://stackoverflow.com/questions/42623590/python-selenium-move-to-element-not-working – JustBeingHelpful Mar 02 '23 at 05:07

1 Answers1

2

You are using a wrong path, in fact if you open the devtools and search //div[@class='actions-toolbar']/div[@class='primary']/button[1] it will find 3 results and the one you want is the third one. To select if you have to replace find_element with find_elements and put [2] at the end.

download_button_path = "//div[@class='actions-toolbar']/div[@class='primary']/button[1]"
driver.find_elements(By.XPATH, download_button_path)[2].click()

Alternatively, you can use a more precise xpath which finds only the element you want.

download_button_path = "//div[@class='payment-method _active']//button[@class='action primary checkout']"
driver.find_element(By.XPATH, download_button_path).click()
sound wave
  • 3,191
  • 3
  • 11
  • 29
  • thank you for the help, I was going around and around to try to find the solution, when it was right there. Thank you again for noticing that I was not "going" to the right button. It works now ;) – flolivei Mar 03 '23 at 18:38