Selenium python click button - python

I just can't make the button click and go the the next page. I tried the following so far
<div class="step__footer">
<button class="step__footer__continue-btn btn " type="submit" name="button">
<span class="btn__content">Continue to payment method</span>
<i class="btn__spinner icon icon--button-spinner"></i>
</button>
<a class="step__footer__previous-link" href="https://checkout.shopify.com/946304/checkouts/1b6e3391268707abb18850300b89e59?step=contact_information">
<svg class="previous-link__icon icon--chevron icon" viewBox="0 0 6.7 11.3" height="11.3" width="6.7" xmlns="http://www.w3.org/2000/svg">
Return to customer information
</a>
</div>
driver = webdriver.Firefox()
driver.implicitly_wait(1) # seconds
driver.find_element_by_css_selector("step__footer__continue-btn btn").click()
driver.implicitly_wait(1) # seconds
driver.find_element_by_xpath("/html/body/div[2]/div/div[2]/div[2]/div/form/div[2]/button").click()
driver.implicitly_wait(1) # seconds
driver.find_element_by_name("button").click()
driver.implicitly_wait(1) # seconds
elem.send_keys(Keys.RETURN)
driver.implicitly_wait(1) # seconds
driver.find_element_by_css_selector("div.step__footer>button").click()
driver.implicitly_wait(1) # seconds
driver.find_element_by_css_selector("html.multi-step.mac.firefox.desktop.page--no-banner.page--logo-main.page--show.js.flexbox.flexboxlegacy.rgba.multiplebgs.boxshadow.opacity.cssanimations.csstransitions.generatedcontent.svg.inlinesvg.cors.boxsizing.display-table.pointerevents.placeholder.mediaqueries.floating-labels body div.content div.wrap div.main div.main__content div.step form.edit_checkout.animate-floating-labels div.step__footer button.step__footer__continue-btn.btn").click()
driver.implicitly_wait(1) # seconds
driver.find_element_by_link_text("Continue to payment method").click()
driver.implicitly_wait(1) # seconds
driver.find_elements_by_class_name("step__footer__continue-btn btn ").click()
driver.implicitly_wait(1) # seconds
driver.findElementByXpath("//div[#type='submit'][#name='button']").click();
EDIT
The key was to relocate the elements, to reload. Since I was clicking through a form, the underlying code changed.
the driver.find_element_by_xpath("//button[#type='submit'][#name='button']").click() could not find elements because of that. After reloading with driver.get ("%s/%s:%s" % (str(sys.argv[4]), str(sys.argv[2]), str(sys.argv[3]))) it worked.
Also look at the log in case some badly formatted command interrupts the flow.

You have many mistakes in your selectors, try one of those
driver.find_element_by_css_selector(".step__footer__continue-btn.btn").click() # for class with css_selector you need '.' in the beginning
driver.find_element_by_class_name("step__footer__continue-btn").click() # by_class_name gets only one class
driver.find_element_by_xpath("//button[#type='submit'][#name='button']").click() # type='submit' and name='button' are <button> tag attributes, not div
You can also try using explicit wait
WebDriverWait(driver, 10).until(expected_conditions.visibility_of_element_located((By.class_name, "step__footer__continue-btn"))).click()
Edit
Sometimes button element area is wider than the element that can receive click. You can try to click on elements in "lower" level
driver.find_element_by_class_name("btn__content").click() # <span> tag
# or
driver.find_element_by_class_name("btn__spinner").click() # <i> tag

Related

ElementNotInteractableException: Message: Element <button class="btn btn-outline-light btn-icons" type="button"> could not be scrolled into view

I am trying to press a the download on this page
https://data.unwomen.org/data-portal/sdg?annex=All&finic[]=SUP_1_1_IPL_P&flocat[]=478&flocat[]=174&flocat[]=818&flocat[]=504&flocat[]=729&flocat[]=788&flocat[]=368&flocat[]=400&flocat[]=275&flocat[]=760&fys[]=2015&fyr[]=2030&fca[ALLAGE]=ALLAGE&fca[<15Y]=<15Y&fca[15%2B]=15%2B&fca[15-24]=15-24&fca[25-34]=25-34&fca[35-54]=35-54&fca[55%2B]=55%2B&tab=table
i am using python selenium with firefox and this is what i tried:
driver.set_page_load_timeout(30)
driver.get(url)
time.sleep(1)
WebDriverWait(driver, timeout=20).until(EC.presence_of_element_located((By.ID, 'SDG-Indicator-Dashboard')))
time.sleep(1)
download_div = driver.find_element(By.CLASS_NAME, 'float-buttons-wrap')
buttons = download_div.find_elements(By.TAG_NAME, 'button')
buttons_attributes = [i.get_attribute('title') for i in buttons]
download_button_index = buttons_attributes.index('Download')
buttons[download_button_index].location_once_scrolled_into_view
buttons[download_button_index].click()```
i keep getting the same error:
ElementNotInteractableException: Message: Element <button class="btn btn-outline-light btn-icons" type="button"> could not be scrolled into view
eventho i am getting the correct element and i tried using js like this:
```driver.execute_script("return arguments[0].scrollIntoView(true);", element)```
also did not work.
You have to modify the XPath, try the below code:
driver.get("https://data.unwomen.org/data-portal/sdg?annex=All&finic[]=SUP_1_1_IPL_P&flocat[]=478&flocat[]=174&flocat[]=818&flocat[]=504&flocat[]=729&flocat[]=788&flocat[]=368&flocat[]=400&flocat[]=275&flocat[]=760&fys[]=2015&fyr[]=2030&fca[ALLAGE]=ALLAGE&fca[<15Y]=<15Y&fca[15%2B]=15%2B&fca[15-24]=15-24&fca[25-34]=25-34&fca[35-54]=35-54&fca[55%2B]=55%2B&tab=table")
driver.implicitly_wait(15)
time.sleep(2)
download_btn = driver.find_element(By.XPATH, "(.//button[#type='button' and #title='Download'])[2]")
download_btn.location_once_scrolled_into_view
time.sleep(1)
download_btn.click()
1.You need to make sure you are giving enough time to complete page loading
2.Once you started to find button element , it's better to use try/catch blocks multiple times and put sleep function when exception occures to provide appropriate time to load scripts and elements.
3.Try finding by xpath instead of finding elements by indexes and be aware that you need to use the index [1] instead of [0] in a xpath string

Not able to click on elements in a dropdown menu using selenium

I'm trying to create an automated web session where I log onto a website and select an option from a dropdown menu. I'm able to get to the page using selenium but I'm unable to click on the bar with opens a drop down menu and then select the option I want. Here is a screenshot of the page and it's HTML Code:
[![enter image description here][1]][1]
[![enter image description here][2]][2]
I would like to click on the 'Degraded Performance' option from the dropdown. I'm a bit stuck here because the HTML of the dropdown does not resemble [this one][3] at all (no way to 'select'). I've also tried watching YouTube videos to no success :(. Here is the script I'm running:
#login to status page if server status is not 'Ok'
driver = webdriver.Safari()
wait = WebDriverWait(driver, 20)
driver.get('https://manage.statuspage.io/login')
email = wait.until(EC.visibility_of_element_located((By.ID, "email")))
email.clear()
email.send_keys(user)
wait.until(EC.visibility_of_element_located((By.ID, "login-btn"))).click()
wait.until(EC.visibility_of_element_located((By.ID, "login-submit"))).click()
password = wait.until(EC.visibility_of_element_located((By.ID, "password")))
password.clear()
password.send_keys(passw)
driver.find_element_by_id('login-submit').click()
#Go to correct component
wait.until(EC.visibility_of_element_located((By.LINK_TEXT, "Components"))).click()
driver.get('https://manage.statuspage.io/pages/hfxvt9zqtn8m/components/g39hxh3gq0bc/edit')
#Change status
wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "status-dropdown__value-container status-dropdown__value-container--has-value css-1b6odlt"))).click()
#here click on 'degraded performance'
#save
driver.find_element_by_id('btn-save-component').click()
The line ```wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "status-dropdown__value-container status-dropdown__value-container--has-value css-1b6odlt"))).click()``` returns a timeout exception.
Any help would be really great!
HTML in text format:
<div class="status-dropdown__control css-4avucx-control"><div class="status-dropdown__value-container status-dropdown__value-container--has-value css-1b6odlt"><div class="status-dropdown__single-value css-lrg2au-singleValue" style="opacity: 1; transition: opacity 1ms;"><div class="_2cgnn8jOgeTLsVfOQFh5Rs"><i class="component-status page-colors text-color degraded_performance"></i><span style="padding-left: 8px; padding-bottom: 0px;">Degraded performance</span></div></div><input id="react-select-2-input" readonly="" tabindex="0" class="css-62g3xt-dummyInput" value=""></div><div class="status-dropdown__indicators css-t5ibhw"><div aria-hidden="true" class="status-dropdown__indicator status-dropdown__dropdown-indicator css-gg6ksl-indicatorContainer"><span role="img" aria-label="open" class="css-rq2oqu"><svg width="24" height="24" viewBox="0 0 24 24" role="presentation"><path d="M8.292 10.293a1.009 1.009 0 000 1.419l2.939 2.965c.218.215.5.322.779.322s.556-.107.769-.322l2.93-2.955a1.01 1.01 0 000-1.419.987.987 0 00-1.406 0l-2.298 2.317-2.307-2.327a.99.99 0 00-1.406 0z" fill="currentColor" fill-rule="evenodd"></path></svg></span></div></div></div>
[1]: https://i.stack.imgur.com/62NnJ.png
[2]: https://i.stack.imgur.com/zMbo0.png
[3]: https://stackoverflow.com/questions/7867537/how-to-select-a-drop-down-menu-value-with-selenium-using-python
See you can not use Select from Selenium since that is meant for drop down built using Select and option tag.
instead I would suggest you to click on Degraded Performance directly.
driver.find_element_by_xpath("//span[contains(text(),'Degraded Performance')]").click()
also I think first you will need to click on drop down bar, then the above code should work, probably will have to use Explicit wait as well.
Update 1 :
instead of
wait.until(EC.visibility_of_element_located((By.CLASS_NAME, "status-dropdown__value-container status-dropdown__value-container--has-value css-1b6odlt"))).click()
try this :
wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div[class^='status-dropdown__single-value']+input"))).click()

Validating Pin-Pad form using Selenium Python

I am trying to input code on a pin pad form available on a website and get it validated. However, I am getting a validation error. I fear the clicked pin buttons are not being read by the website's script. Can anyone help me with this? I am attaching the code as well as the page source code.
The UI of website looks like this
The div class on website which contains the keypad is as follows:-
<div class="pin_pad">
<span id='keypad1' onmouseout="this.className=''" onmouseover="this.className='pin_hover'">1</span>
<span id='keypad2' onmouseout="this.className=''" onmouseover="this.className='pin_hover'">2</span>
<span id='keypad3' onmouseout="this.className=''" onmouseover="this.className='pin_hover'">3</span>
<span id='keypad4' onmouseout="this.className=''" onmouseover="this.className='pin_hover'">4</span>
<span class="submit_btn" onmouseout="this.className='submit_btn'" onmouseover="this.className='submit_btnpin_hover'" onclick="return validate();">Submit</span>
</div>
My pin is "4444". I am trying to use the .click() method to get "4" clicked. Although I can see that "4" has been clicked 4 times, upon submit, the page shows a validation error. Can anyone help me in solving this problem? Here's my code in python:-
pinpad = driver.find_elements_by_class_name('pin_pad')
element = driver.find_element_by_xpath("//span[text()=4]").click()
for k in range(4):
actionChains = ActionChains(driver)
actionChains.context_click(element).perform()
time.sleep(1)
driver.find_element_by_xpath("//span[text()='Submit']").submit()
Instead of
context_click(element).perform()
do this :
move_to_element(key4).click().perform()
context_click is for right click and move_to_element() is for moving your mouse cursor to the specify element.
Brief explanation :
You can introduce WebDriverWait for more stability, and I don't think you need to do context_click() instead it is move_to_element() plus ActionChains object creation optimization and instead of submit you may wanna use click(). Check out the code below :
pinpad = driver.find_elements_by_class_name('pin_pad')
key4 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "span#keypad4"))).click()
actionChains = ActionChains(driver)
for k in range(4):
actionChains.move_to_element(key4).click().perform()
sleep(1)
wait.until(EC.element_to_be_clickable((By.XPATH, "//span[text()='Submit']"))).click()

Selenium - How to debug timeout for iframe > input field?

I'm stuck writing a Selenium WebDriver script for Instagram web login. I think I switched to the appropriate iframe but WebDriver keeps timing out when it should locate the user input field.
Relevant source from Instagram site:
https://instagram.com/accounts/login/
<iframe class="hiFrame" data-reactid=".0.0.0.1.0.1.0.0.$frame" src="https://instagram.com/accounts/login/ajax/?targetOrigin=https%3A%2F%2Finstagram.com" scrolling="no" seamless="">
<!DOCTYPE html>
<html class="hl-en not-logged-in " lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<body class="LoginFormChrome ">
<div class="LoginFormPage" data-reactid=".0">
<form data-reactid=".0.0">
<p class="lfField" data-reactid=".0.0.0">
<label class="lfFieldLabel" data-reactid=".0.0.0.0">
<input class="lfFieldInput" type="text" data-reactid=".0.0.0.1" value="" autocorrect="false" autocapitalize="false" maxlength="30" name="username">
</p>
Source from Selenium script:
login_url = 'https://instagram.com/accounts/login/'
profile_url = '<path_firefix_profile>'
user = '<user_name>'
#login
my_profile = FirefoxProfile(profile_url)
self.driver = webdriver.Firefox(my_profile)
self.driver.get(login_url)
self.driver.implicitly_wait(10)
my_iframe = self.driver.find_element_by_css_selector("iframe.hiFrame")
#my_iframe = self.driver.find_element_by_css_selector("iframe:nth-of-type(1)")
#my_iframe = self.driver.find_element_by_tag_name("iframe")
self.driver.switch_to_frame(my_iframe)
try:
element = WebDriverWait(self.driver, 30).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[name='username']")))
user_input = self.driver.find_element_by_css_selector("input[name='username']")
user_input.send_keys(user)
finally:
print('user name input appeared')
Results:
This error results from WebDriver:
File "instagram_firefox.py", line 51, in setUp
element = WebDriverWait(self.driver, 45).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[name='username']")))
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/selenium/webdriver/support/wait.py", line 71, in until
raise TimeoutException(message)
I tried to verify that the css selector for the input field was correct. On the page, https://instagram.com/accounts/login/, FireFox FireFinder does not recognize the css selector that I used. But if I open another tab with the source of the iframe, https://instagram.com/accounts/login/ajax/?targetOrigin=https%3A%2F%2Finstagram.com, then Firefinder recognizes the css selector that I used. Does this mean I need to manually get the url of the iframe source or should that be done automatically when WebDriver switches to the iframe?
We should wait first for div spinner element to disappear, then we can retrieve that iframe you need:
user = "user"
self.driver.get("https://instagram.com/accounts/login/")
#Wait for spinner to disappear
WebDriverWait(self.driver, 10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR, "div.liSpinnerLayer")))
#Get iframe and switch to it
my_iframe = self.driver.find_element_by_css_selector("iframe.hiFrame")
self.driver.switch_to_frame(my_iframe)
element = WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "input[name='username']")))
element.send_keys(user)

How can I get Selenium Web Driver to wait for an element to be accessible, not just present?

I am writing tests for a web application. Some commands pull up dialog boxes that have controls that are visible, but not available for a few moments. (They are greyed out, but webdriver still sees them as visible).
How can I tell Selenium to wait for the element to be actually accessible, and not just visible?
try:
print "about to look for element"
element = WebDriverWait(driver, 10).until(lambda driver : driver.find_element_by_id("createFolderCreateBtn"))
print "still looking?"
finally: print 'yowp'
Here is the code that I have tried, but it "sees" the button before it is usable and basically charges right past the supposed "wait".
Note that I can stuff a ten second sleep into the code instead of this and the code will work properly, but that is ugly, unreliable, and inefficient. But it does prove that the problem is just that "click" command is racing ahead of the availability of the controls.
I assume the events timeline goes like this:
there are no needed elements on page.
needed element appears, but is disabled:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
needed element becomes enabled:
<input type="button" id="createFolderCreateBtn" />
Currently you are searching for element by id, and you find one on step 2, which is earlier than you need. What you need to do, is to search it by xpath:
//input[#id="createFolderCreateBtn" and not(#disabled)]
Here's the difference:
from lxml import etree
html = """
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
"""
tree = etree.fromstring(html, parser=etree.HTMLParser())
tree.xpath('//input[#id="createFolderCreateBtn"]')
# returns both elements:
# [<Element input at 102a73680>, <Element input at 102a73578>]
tree.xpath('//input[#id="createFolderCreateBtn" and not(#disabled)]')
# returns single element:
# [<Element input at 102a73578>]
To wrap it up, here's your fixed code:
try:
print "about to look for element"
element_xpath = '//input[#id="createFolderCreateBtn" and not(#disabled)]'
element = WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_xpath(element_xpath)
)
print "still looking?"
finally:
print 'yowp'
UPDATE:
Repasting the same with the actual webdriver.
Here's the example.html page code:
<input type="button" id="createFolderCreateBtn" disabled="disabled" />
<input type="button" id="createFolderCreateBtn" />
Here's the ipython session:
In [1]: from selenium.webdriver import Firefox
In [2]: browser = Firefox()
In [3]: browser.get('file:///tmp/example.html')
In [4]: browser.find_elements_by_xpath('//input[#id="createFolderCreateBtn"]')
Out[4]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75110>,
<selenium.webdriver.remote.webelement.WebElement at 0x103f75150>]
In [5]: browser.find_elements_by_xpath('//input[#id="createFolderCreateBtn" and not(#disabled)]')
Out[5]:
[<selenium.webdriver.remote.webelement.WebElement at 0x103f75290>]
UPDATE 2:
It works with this as well:
<input type="button" id="createFolderCreateBtn" disabled />
print time.time()
try:
print "about to look for element"
def find(driver):
e = driver.find_element_by_id("createFolderCreateBtn")
if (e.get_attribute("disabled")=='true'):
return False
return e
element = WebDriverWait(driver, 10).until(find)
print "still looking?"
finally: print 'yowp'
print "ok, left the loop"
print time.time()
Here is what we ended up with. (Thanks to lukeis and RossPatterson.) Note that we had to find all the items by id and then filter by "disabled". I would have preferred a single search pattern, but what can you do?
I think something along these lines should work as well:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
browser = webdriver.Firefox()
wait = WebDriverWait(browser, 30)
wait.until(expected_conditions.presence_of_element_located((By.XPATH, "//*[#id='createFolderCreateBrn' and not(#disabled)]")))
There are already some great answers posted up here, but I thought I would add my solution. Explicit wait etc. are great functions for use in testing with selenium. However explicit wait merely performs the function of a Thread.Sleep() that you can only set one time. The function below is what I used to "Shave off" a few minutes. It waits until the element is "accessible."
//ALTERNATIVE FOR THREAD.SLEEP
public static class Wait
{
//public static void wait(this IWebDriver driver, List<IWebElement> IWebElementLIst)
public static void wait(this IWebDriver driver, By bylocator)
{
bool elementPresent = IsPresent.isPresent(driver, bylocator);
while (elementPresent != true)
{
Thread.Sleep(1000);
elementPresent = IsPresent.isPresent(driver, bylocator);
}
}
}
It is in C#, but to adapt it would not be that difficult. Hope this helps.

Categories