Selenium can't find radio button - python

I'm automating the testing process we have in servicenow, but I can't select a radio button in a form. I've used multiple selectors to fix this but nothing has worked.
ServiceNow HTML:
these are the selectors I have used:
driver.find_element_by_css_selector('input[value="Add"]').click()
driver.find_element_by_xpath('//input[#value="Add"]').click()
None of these have worked and there's not iframe tag in the body to swicth to. Thank you!

The following are a few reasons why I couldn't find an element.
Currently on the wrong window/frame.
Synchronization issues - script is looking before the element has loaded. Solved with explicit waits. (see #cruisepandey's answer)
The element was different due to mobile vs desktop. Should be noticable if you disable headless. I advise dumping the HTML from selenium just to be sure.
When I'm unsure I'll start trying to find it's parent element, walking up the scope until I'm able to get a proper element. That's usually where I figure out what the problem was.
Can I find the parent label element?
Can I find the grandparent div element?
Can I find the greatgrandparent fieldset?
And so on...

You can try with expicit wait :
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.XPATH, "//input[#value='Add']")))
element.click()
Imports :
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Update 1 :
wait = WebDriverWait(driver, 10)
radioBtn = wait.until(EC.element_to_be_clickable((By.XPATH, "//input[#value='Add']")))
driver.execute_script("arguments[0].checked = true;", radioBtn)

Related

Sellenium, cant find button like in Instagramm

hi
The problem is that selenium cannot find the button click like, as soon as it does not work through xpath, always gives different errors. First error
In general, the bot enters Instagram by posts (according to the global hashtag), but cannot like. Need to find this button
Your code raises the error list object has no attribute click because the command like = browser.find_elements(...) returns a list of elements, so if you want to click one element you have to specify its index in the list, for example like[0].click() instead of like.click().
By looking at the HTML we see that the like button has a svg descendant with attribute aria-label='Like', so we can first target the svg with //*[local-name()='svg'][#aria-label='Like'] and then go back to the button parent with /parent::div/parent::button.
By using WebDriverWait and EC (expected conditions) we can be sure that the button is visible and clickable on the page.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
xpath_like_button = "//*[local-name()='svg'][#aria-label='Like']/parent::div/parent::button"
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, xpath_like_button))).click()

What is the correct way to correctly identify an object via Python and Selenium?

I am currently dabbling in Python in combination with Selenium. I can't get any further at one point.
Enclosed you can see three screenshots. At https://www.easycredit.de I already click on the button (1). After that I get to the next page. I would like to click this button (2) now. In Screenshot 3 you can see the location in the source code.
# link to Chromedriver
browser = webdriver.Chrome('/usr/local/bin/chromedriver')
button = browser.find_element(By.CLASS_NAME, 'econ-button btn btn-primary')
button.click()
The error:
NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":".econ-button btn btn-primary"}
(Session info: chrome=104.0.5112.79)
Here are my questions:
hy does it not work with this code?
How do you find out with which procedure it works best in a case like this?
How do you choose whether to identify an element by XPATH, ID etc.?
Thanks
econ-button btn btn-primary are actually 3 class names.
By.CLASS_NAME gets only single class name parameter.
To work with locators containing multiple class names you can use By.XPATH or By.CSS_SELECTOR.
As for me both the above methods are good, each of them having several cons and pros.
So, here you can use
browser.find_element(By.CSS_SELECTOR, 'button.econ-button.btn.btn-primary')
Or
browser.find_element(By.XPATH, "//button[#class='econ-button btn btn-primary']")
Generally, you can use By.CSS_SELECTOR or By.XPATH. No need to utilize By.ID or By.CLASS_NAME since they are actually internally immediately translated to By.CSS_SELECTOR or By.XPATH :)
Some people preferring to use By.CSS_SELECTOR while others prefer By.XPATH.
As I mentioned previously, each of the above 2 methods having cons and pros.
For example you can locate elements by their texts with XPath only. XPath supports locating parent element based on their child nodes.
On the other hand XPath will not work so good on Firefox driver while it works perfectly on Chrome driver etc.
UPD
The locator for the second nein radio button can be:
"//label[.//input[#data-econ-property='kreditdaten-beduerfnisfragen-flexibilitaetGewuenscht'][#value='radio3']]"
So, Selenium click can be done with
browser.find_element(By.XPATH, "//label[.//input[#data-econ-property='kreditdaten-beduerfnisfragen-flexibilitaetGewuenscht'][#value='radio3']]").click()
And so on with other buttons
The element Zu den finanziellen Angaben is a dynamic element. So to click element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following locator strategies:
Using CSS_SELECTOR:
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.econ-button.btn.btn-primary[value='Zu den finanziellen Angaben']"))).click()
Using XPATH:
WebDriverWait(browser, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#class='econ-button btn btn-primary' and #value='Zu den finanziellen Angaben']"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Selenium: How to click a label

I'm trying to click this object with selenium (pyhton) using the code:
driver.find_element_by_('publicForm_customFields').click()
But I'm receiving this error:
id="publicForm_customFields" tabindex="0" type="radio" value="value"> is not clickable at point (480, 98). Other element would receive the click: value
"Other element would receive the click" means that you have another element over your element. There are a couple of options to get around this:
Try to find another element above in the DOM tree and click on it.
Use js click, you need to write a function like this:
def js_click(self, element):
element = driver.find_element_by_id("myid")
driver.execute_script("arguments[0].click();", element)
js script will click on the element even if it is intersected by another
There might be two possibilities:
1- Your locator to find element might be wrong or not unique.
2- You need to apply explicit wait till element is ready [load successfully] to be clickable.
Hope above possibilities might help you out, Or you share the link of the sight so I might debug correctly.
You are not passing any find method to the driver. Try refactoring the code to:
driver.find_element_by_id('publicForm_customFields').click()
Also, try using some sort of wait so the driver does not click before the page/element is loaded.
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.ID, 'publicForm_customFields'))).click()

.click() and .send_keys() methods not being recognized Python Selenium

I'm using Selenium in Python to click a text entry field and write some text into it. Neither the .click() nor .send_keys() methods are being recognized. Can someone help with this?
Also, is there a way to stop Selenium from printing to the console automatically? My program is console-based and Selenium is writing things to an input() that I gave because it prints to the console.
Here is a code snippet:
url = "https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65"
browser = webdriver.Edge("Web Scrapers\msedgedriver.exe")
browser.get(url)
textbox = browser.find_element_by_id("LocationSearch_input")
textbox.click()
textbox.send_keys(zipcode)
textbox.send_keys(Keys.ENTER)
you could try the explicitWait hope this will work for you
WebDriverWait(browser,10).until(EC.element_to_be_clickable((By.XPATH,"//input[#type='text']"))).send_keys("20874",Keys.RETURN)
I would suggest you to do it with explicit wait.
I am giving this answer, cause none of the answer's are really using Explicit waits with ID attribute :
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65")
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.ID, "LocationSearch_input"))).send_keys('60007' + Keys.RETURN)
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "div[class^='CurrentConditions--dataWrapperInner']"))).click()
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
From what I can tell, everything is working fine here, however you are pointing your textbox variable to the wrong HTML element.
LocationSearch_input is a hidden label that isn't directly attached to the searchbox. I would try pointing it to
SearchInput--SearchInput--M7lKl SearchInput--enableSearchIcon--1Ugsx, one of the parent elements.
At least testing in firefox, it's a timing thing. The click works. The error of element not interactable (not reachable by keyboard) comes off of the send_keys line. If we wait after the click(), the element becomes reachable by keyboard.
The following could probably be refined (really don't like sleep, but sometimes it works), but works for me:
url = "https://weather.com/weather/today/l/69ef4b6e85ca2de422bea7adf090b06c1516c53e3c4302a01b00ba763d49be65"
browser.get(url)
browser.find_element_by_id('LocationSearch_input').click()
time.sleep(5)
browser.find_element_by_id('LocationSearch_input').send_keys('Boston')
At that point you need to click on whichever of the 10 options is what you really want.

How to handle Python Selenium recurring loading modals and stay DRY?

I'm using python 3.6 and selenium 3.8.1, Chrome browser to simulate users entering an order. The app we use has a particularly frustrating implementation for automation - a loading modal will pop up whenever a filter for a product is loading, but it does not truly cover elements underneath it. Additionally, load time fluctuates wildly, but with an upper bound. If I don't use excessive sleep statements, selenium will either start clicking wildly before the correct objects are loaded or clicks on the element but, of course, hits the loading modal. (Fun side note, the loading modal only fills the screen view, so selenium is also able to interact with items below the fold. :P)
To get around this:
def kill_evil_loading_modal(self):
# i pause for a second to make sure the loader has a chance to pop
time.sleep(1)
# pulling locator type and from another file: ("id","locator_id")
loading_modal = ProductsLocators.loading_modal_selector
# call a function that returns true/false for object if exists
check_for_evil = self.is_element_exist(*loading_modal)
while check_for_evil == True:
check_for_evil = self.is_element_exist(*loading_modal)
This works great! Where I had a ton of evil time.sleep(x) statements to avoid the loading modal, I'm now catching it and waiting until it's gone to move forward.
If I only had to deal with that two or three times, I would move on. Sadly, this loading modal hits after every click ... so this is what my main script looks like now:
new_quote02_obj.edit_quote_job(**data)
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_product_dropdown()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_product_dropdown_link()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.select_category_dropdown(scenario_data['category_name'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.select_market_dropdown(scenario_data['local_sales_market'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.add_products_job(scenario_data['product_list_original'])
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.click_done_btn()
new_quote03_obj.kill_evil_loading_modal()
new_quote03_obj.next_btn_page()
How can I refactor to stay DRY?
If you want to wait until modal disappeared and avoid using time.sleep() you can try ExplicitWait:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait as wait
wait(driver, 10).until_not(EC.visibility_of_element_located(("id", "locator_id")))
or
wait(driver, 10).until(EC.invisibility_of_element_located(("id", "locator_id")))
This should allow you to wait up to 10 seconds (increase delay if needed) until element with specified selector ("id", "locator_id") will become invisible
If modal appears after each click you can implement your own click method, like
def click_n_wait(by, value, timeout=10):
wait(driver, timeout).until(EC.element_to_be_clickable((by, value))).click()
wait(driver, timeout).until(EC.invisibility_of_element_located(("id", "locator_id")))
and use it as
click_n_wait("id", "button_id")
As you mentioned in your question a loading modal will pop up whenever a filter for a product is loading irespective of the loader cover elements underneath it or not you can simply wait for the next intended element with which you want to interact with. Following this approach you can completely get rid of the function kill_evil_loading_modal() which looks to me as a overhead. As a replacement to kill_evil_loading_modal() function you have to invoke WebDriverWait() method along with proper expected_conditions as required as follows :
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 as EC
# other code
WebDriverWait(driver, 2).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_A"))).click()
WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_B"))).click()
WebDriverWait(driver, 3).until(EC.element_to_be_clickable((By.XPATH, "xpath_of_element_C"))).click()

Categories

Resources