Setting value for input element in selenium Python - python

I am trying to change the value of an input tag element.
Here is the tag: <input type="hidden" id="hiRequestAccessType" data-bind="value: requestAccessTypeStr" value="2">
I want to change value to "2,1".
Based on discussion at Set value of input instead of sendKeys() - selenium webdriver nodejs, I tried using execute_script, but value remains unchanged.
I tried this:
passwordcheck_input_element = driver.find_element_by_xpath('//*[#id="hiRequestAccessType"]') . ###THIS DOESNT THROW ERRORS
new_value = "2,1"
driver.execute_script("arguments[0].value = arguments[1].toString()", passwordcheck_input_element, new_value)
# driver.execute_script("arguments[0].value = '" + new_value + "'", passwordcheck_input_element) . ###TRIED THIS IN LIEU OF ABOVE
For either alternative, code runs but value remains unchanged from visual inspection. I also tried the above two alternatives using 'setAttribute' instead of directly, same (no change) result.
Note that the webpage is a form where clicking on a check box changes value to "2,1" as desired. (But if I try finding the check box element, I get the message it is not clickable, hence this route).
Now, what's weird is I know it's doing something right behind the scenes because I tried querying value attribute before and after my execute_script call and it prints out the new value correctly for latter. However, as I said, the UI doesnt show this change; further, when I move on and hit the submit buttom further down, it's the old value that gets used because I am not getting the page that should load if the new value were used.

Could you please try the code below?
passwordcheck_input_element = driver.find_element_by_id("hiRequestAccessType")
driver.execute_script("arguments[0].value = '2,1';", passwordcheck_input_element)
You can also control the checkbox object via javascript execution if it is not clickable.
driver.execute_script("document.getElementById('hiRequestAccessType').checked = true;")

driver.find_element_by_xpath('//*[#id="hiRequestAccessType"]').setAttribute("value", "1")
Short you can select with xpath or css name element after selection you can change with .setAttribute function your value. Also you can get current selected element value with getAttribute function.For simulate checkbox click : .setAttribute("checked", "checked")

Related

Python Selenium, Input field returns an ElementNotInteractableException even though element is interactable

SOLVED:
It seems like this single input field would be not interactable unless it was clicked in the most recent 0.1 seconds. To solve that the following code was used:
ActionChains(self.driver).move_to_element(input).click().send_keys("200").perform()
This way the focus stays on the element and the input works. Interestingly, if input.send_keys() is called this still does not work.
Problem:
After pressing a button on the website, a popup window opens up which contains multiple input fields which are generated by react. Most of these are accessible. However, one of them is not and returns an ElementNotInteractableException error. I have tried the most common solutions but those do not work.
The interesting part is that when the element is accessed manually from the front end, it can be interacted with. The element also is shown normally in a screenshot which is taken upon an exception being thrown
Solutions tried:
Increase implicit wait until 1 minute,
Add explicit wait untill 1 minute
Use different finding methods for the element
Reorder test to see if other elements influence it (all possible orders have failed)
Add Actionchains Move to and Click. The move to and click work (I can see the element being selected with a blue outline, but the input still feels)
Use Javascript to insert the string into the input fields.value
Code block on which the error occurs:
#this input element is next to it in the same parent element
dropdownparent = elems[2].find_element_by_xpath(".//div[#role='combobox']")
dropdowninput = dropdownparent.find_element_by_css_selector("input")
f.inputtext(dropdowninput, "Coulance", True )
#reobtain the parent items to avoid a stale element reference error
modal = self.driver.find_element_by_class_name("component-window")
body = modal.find_element_by_class_name("body")
elems = body.find_elements_by_xpath("./div")
required = elems[2].find_elements_by_class_name("required")
inputparent = required[1].find_element_by_class_name("input")
input = inputparent.find_element_by_css_selector("input")
#error occurs on next line
f.inputtext(input, "200")
Error log:
https://pastebin.com/ihqCvjfj
its long but its a very standard elementnotaccessible
Any suggestions would be appreciated, I will update the solutions tried section whenever I try something
Element not interactable comes when the element is out of clickable area or some other element is covering up that element.
You can try by scrolling the page to an element or you can set input value by executing javascript, something like this:
element = inputparent.find_element_by_css_selector("input")
driver.execute_script("""arguments[0].value = arguments[1];""", element, "some input value")

Can't make webdriver.click() or .submit() work in loop (python)

I want to scrape data from an HTML table for different combinations of drop-down values via looping over those combinations. After a combination is chosen, the changes need to be submitted. This is, however, causing an error since it refreshes the page.
This is what I've done so far:
from selenium import webdriver
from selenium.webdriver.support.ui import Select
import time
browser.get('https://daten.ktbl.de/feldarbeit/entry.html')
# Selecting the constant values of some of the drop downs:
fertilizer = Select(browser.find_element_by_name("hgId"))
fertilizer.select_by_value("2")
fertilizer = Select(browser.find_element_by_name("gId"))
fertilizer.select_by_value("193")
fertilizer = Select(browser.find_element_by_name("avId"))
fertilizer.select_by_value("383")
fertilizer = Select(browser.find_element_by_name("hofID"))
fertilizer.select_by_value("2")
# Looping over different combinations of plot size and amount of fertilizer:
size = Select(browser.find_element_by_name("flaecheID"))
for size_values in size.options:
size.select_by_value(size_values.get_attribute("value"))
time.sleep(1)
amount= Select(browser.find_element_by_name("mengeID"))
for amount_values in amount.options:
amount.select_by_value(amount_values.get_attribute("value"))
time.sleep(1)
#Refreshing the page after the two variable values are chosen:
button = browser.find_element_by_xpath("//*[#type='submit']")
button.click()
time.sleep(5)
This leads to the error: selenium.common.exceptions.StaleElementReferenceException: Message: The element reference of <option> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed.
Obviously the issue is that I did indeed refresh the document.
I tried it with .submit():
button = browser.find_element_by_xpath("//*[#type='submit']")
button.submit()
This leads to the error: selenium.common.exceptions.NoSuchElementException: Message: Unable to locate element: ./ancestor-or-self::form
Time seems not to be the issue here (adding time.sleep or b.implicit.wait didn't change anything).
How can I update the page without breaking from the loop?
EDIT since it was marked as duplicate: I believe that this question does not answer my problem posed here, at least not on my level of python skills, even though the error message is similar. In the other question the problem was solved via added a wait(driver, x) and an expected condition if I'm not mistaken. Here on the other hand the issue was indeed that I did not call the relevant drop-down inside AND outside the loop, as correctly stated by Zaraki Kenpachi.
You need to initiate size select outside the loop to collect sizes and inside loop to grab current page state.
size = Select(browser.find_element_by_name("flaecheID"))
for size in [item.get_attribute("value") for item in size.options]:
size_select = Select(browser.find_element_by_name("flaecheID"))
size_select.select_by_value(str(size))
button = browser.find_element_by_xpath("//input[#type='submit']")
button.click()

Trouble when automating button click selenium

So I am trying to fill out a form on this site. Every time I try to click the submit button at the end, using what I believe is the correct id, it just gives me an error. Here is a code snippet:
from selenium import webdriver
thePassword = "asdf123"
print("Desired name: ")
name = raw_input()
print("Desired Last Name: ")
userLastName = raw_input()
browser = webdriver.Firefox()
browser.get('https://www.panerabread.com/en-us/mypanera/registration-page.html')
firstName = browser.find_element_by_id('join_first_name')
firstName.send_keys(name)
lastName = browser.find_element_by_id('join_last_name')
lastName.send_keys(userLastName)
emailElem = browser.find_element_by_id('join_email')
emailElem.send_keys("asdafasda" + "#gmail.com")
emailConfirm = browser.find_element_by_id("join_confirm_email")
emailConfirm.send_keys("asdafasda" + "#gmail.com")
password = browser.find_element_by_id("join_password")
password.send_keys("thePassword")
passwordConfirm = browser.find_element_by_id("join_confirm_password")
passwordConfirm.send_keys("thePassword")
phoneA = browser.find_element_by_id("phone_number_a")
phoneA.send_keys("231")
phoneB = browser.find_element_by_id("phone_number_b")
phoneB.send_keys("123")
phoneC = browser.find_element_by_id("phone_number_c")
phoneC.send_keys("2310")
tos = browser.find_element_by_id("join_i_agree")
tos.click()
browser.execute_script("$('#join_password').get(0).scrollIntoView();")
#browser.implicitly_wait(10)
# And then perform the click
browser.find_element_by_id("join_card_not_available").click()
browser.find_elements_by_css_selector("#join-now-primary")[1].click()
print "Your email is: " + "asdafasda" + "#gmail.com"
print "Your password is: " + thePassword
My question is, how can I submit the form at the end of my script?
Edit: There is no error. The problem is that it doesn't click the button I want it to at all. I tried running the below code on a seperate file and it worked, however when you run it with this entire script it does not work.
This was a weird one... it took me a minute to figure out what was going on. The problem is that there are actually two elements that have that id on the page (which is a no-no according to the HTML standard... but alas it happens). One on the bottom of the page that you are looking at and another on the Sign In popup. If you click the Sign In button at the top of the page, you will see the (first) Sign In button on the popup. Because it is hidden, your code wouldn't click on it. Anyway... to the solution.
There are a few ways you can handle this, any of them valid. I would do this.
browser.find_elements_by_css_selector("#join-now-primary")[1].click()
What this is doing is using a CSS selector to get all the elements with ID=join-now-primary. The CSS selector is #join-now-primary which means id (#) of join-now-primary. Because it uses .find_elements (plural), it will get both. We then use [1] to get the 2nd element (0-based index, so 1 is the 2nd) and then click on it.
EDIT
My guess is that it's a timing issue that is causing the code to work on its own but not in your script. Put a breakpoint on the first line and step through each line and make sure that it executes. Does it work? If I were to guess again... it's likely the line right before the Join Now click. That click has an animation that closes the credit card picture. I would wait for that section to become invisible using the code below
element = WebDriverWait(browser, 5).until(EC.invisibility_of_element_located(By.ID('panera-card-section')))
browser.find_elements_by_css_selector("#join-now-primary")[1].click()
You didn't really ask a question but it's likely you need to look at the WebElement class's methods and properties.
Looks like the button might not be in the visible portion of the window based on your code.
WebElement Has a property call that scrolls until an element moves into view.
If an element is not visible by Selenium definition, it is not clickable.
Even though you use the guts of the page to drive it, selenium wants to pretend it is testing human like interaction and so provides an artificial constraint.
You can bypass that by executing JavaScript click() on the element.

WebDriver python equivalent of "refreshed" expected condition

So, using WebDriver python binding, I came across a problem that I need to wait until an element is refreshed on the page. Say, I have two radio buttons, and by clicking either of them, a label text is changed.
Currently, if I click on one and get the text and then click on the other and get the text again, I will get the same text although it has changed. Thus, I think I need to wait for the element to be refreshed.
On Java documentation, there is a refreshed expected condition which appears to be useful in this case. But I'm unable to find the python version of it. What is its equivalent? How can I workaround this?
text_to_be_present_in_element() under expected_conditions.py is similar to what you're looking for. If it's not the value that's changing but instead another field like textContent, you could roll a custom solution which is similar to text_to_be_present_in_element().
def attribute_text_is_in_element(text, locator, attribute):
try:
element_text = driver.find_element(locator).get_attribute(attribute)
if text == element_text:
return True
else:
return False
except StaleElementReferenceException:
return False

Selenium Python document.getElementsByClassName()

I'm using Selenium with Python3 to automate entering data into a website.
I have tried looking everywhere for how to deal with selecting an element by class if there is more than one but I can't figure out how to select the accordion-toggle[1]. Nothing happens on selenium but it works fine on any browser. Also, is there any way to just use the regular javascript or jquery commands?:
accordion=find_element_by_class("accordion-toggle"[1])
accordion.click()
#otheraccordion=find_element_by_css_selector("#AdvancedAddress > div.accordion-heading.in > div.accordion-toggle > span.accordionExpandCollapse")
#otheraccordion.click()
StreetNameField=driver.find_element_by_id("Advanced_FindMyParcel_PropertyStreetName")
StreetNameField.send_keys("Sherman")
ZipField=driver.find_element_by_id("Advanced_FindMyParcel_PropertyZip")
ZipField.send_keys("90201")
ZipButton=driver.find_element_by_id("btnSearchFindMyParcels")
ZipButton.click()
You actually can use document.getElementsByClassName() through execute_script() call:
driver.execute_script("document.getElementsByClassName('accordion-toggle')[0].click();")
But I would not go down to executing javascript for such a simple task. Easier to locate the element using find_element_by_class_name():
accordion = driver.find_element_by_class_name('accordion-toggle')
accordion.click()
You are looking for find_element(s)_by_css_selector - reference here - use the css prefix '.classname` to indicate the class.
e.g. to find
<div class='theClass'>
driver.find_elements_by_css_selector('.theClass')
You can also use the By syntax:
driver.find_elements(By.CSS_SELECTOR, '.theClass')
Edit
It seems the problem may be more to Clicking the element, rather than finding it.
Ensure the element is visible
For Chrome, you may need to mimic hovering the mouse over the element before clicking this - see Actions / ActionChains MoveToElement to hover over the element.
For IE, you may need to ensure the browser / frame gets the focus, prior to the element Click - you may need to apply a hack like one of these.
In addition to #alecxe response, I would also suggest using the function find_elements_by_class_name instead of find_element_by_class_name in case there are multiple elements with the same class name.
accordion = driver.find_elements_by_class_name('accordion-toggle')[1] # Selects second element
accordion.click()
Using find_element_by_class_name will return only the first element with that class name.

Categories

Resources