Can selenium recognize aria-uuid as an ID for object recognition? - python

I recently recommended to my devs to add IDs to each element on the project I'm working to make automation more robust, they added in aria-uuid to each element. I cannot get anything to recognize these IDs! I'm wondering if it is even possible?
I'm using python/selenium.
I've tried identifying elements by ID, I've done CSS selectors and xpaths but they have had a history of breaking between new builds.
Relevant html:
input class="short ng-valid ng-not-empty ng-valid-min ng-valid-required" name="question_16" type="number" aria-uuid="question_16_input" ng-required="true" ng-min="0" ng-model="$ctrl.vault['question_16'].value"
def click_element_by_id(self, driver_init, id1, message1, delay1, halt):
try:
element = WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.ID, id1)))
element.click()
except TimeoutException:
if halt:
assert_that(True, message1).is_false()
else:
print(message1)
Each time I get the assertion/timeout error

Ideally, yes you should have been able to recognize each individual elements with respect to their aria-uuid to be used with Selenium provided the generated aria-uuid were static.
As per the HTML you have shared the generated aria-uuid seems to be dynamic. So aria-uuid alone won't help you. In these cases you have to use the aria-uuid along with the other attributes to uniquely identify the elements. To identify this element you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.short.ng-valid.ng-not-empty.ng-valid-min.ng-valid-required[aria-uuid$='_input'][name^='question_']"))).click()
Using XPATH:
WebDriverWait(driver_init, delay1).until(EC.element_to_be_clickable((By.XPATH, "//input[#class='short ng-valid ng-not-empty ng-valid-min ng-valid-required' and contains(#aria-uuid, '_input')][starts-with(#name, 'question_')]"))).click()

It should be possible with a CSS selector [aria-uuid='question_16_input']

Related

Trying to click entry buttons on gleam using selenium but am having trouble identifying the element

Here is the inspect result for the button that says +5 per day
>span class="text user-links entry-method-title ng-scope ng-binding" ng-include="::'views/entry-text/'+entry_method.entry_type+'.html'">
Click For a Daily Bonus Entry"
</span>
<div class="entry-method bonus template" data-remove-popovers="" id="em6129519" ng-class="{expanded: entryState.expanded == entry_method, template: entry_method.template, 'completed-entry-method': !canEnter(entry_method) && isEntered(entry_method)}" ng-repeat="entry_method in ::entry_methods">
here is the HTML given information when I inspect the link/button, I have tried to use XPath, CSS, link text, and class name and it keeps giving me an error saying it cannot identify the element. Does anyone have a suggestion for how to identify this, it is on gleam.io for a giveaway I'm trying to automate this so i don't have to log in and press this everyday. This is my first ever web interfacing project with python.
Here is my most recent try
driver.maximize_window()
time.sleep(10)
driver.execute_script("window.scrollTo(0, 1440)")
time.sleep(10)
button2 = driver.find_element_by_class_name("text user-links entry-method-title ng-scope ng-binding")
button2.click()
Similar to a previous issue, Selenium find_element_by_class_name and find_element_by_css_selector not working, you can't have spaces in your class name when using driver.find_element_by_class_name. Instead, find the element via css_selector and replace each space with a dot.
driver.find_element_by_css_selector("span.text.user-links.entry-method-title.ng-scope.ng-binding")
That'll fix what you have above, but keep in mind there are other ways to make selenium actions more reliable (eg. WebDriverWait, etc). And there may be a cleaner selector to use than the one above.
I believe the element you want to access is contained within an "iframe", thus you must first switch to iframe before you can access it using selectors.
driver.switch_to.frame(x.find_element_by_xpath("PUT IFRAME XPATH HERE"))

Finding an element whose Xpath is unique to each login

I am coding a python web automation selenium script.
In the script, I use driver.find_element_by_xpath('xpath') to find elements on Binary.com. This means I would have to preload Binary.com and copy xpaths of the elements I need to find. For most elements the method works but for a few I realised that the Xpath is unique to each login.
For example, if I login in now and try to copy the xpath of a certain element it will be //*[#id="tp1602844250562"] but if the page is reloaded or I try to login on a different window the xpath would have then changed to //*[#id="tp1602844157070"]. Please note they are not the same id numbers. This means I cannot use one xpath on a separate page login
The desired element has an HTML code:
<input type="text" class="time hasTimepicker" tab-index="-1" value="00:00" readonly="" id="tp1602844157070">
Refer to the supplied image for clear html code
You can try below with class instead of id as the id is getting pulled from DB i guess-
//div[#class='date-time']//input[contains(#class,'time')]
Why don't you use the class instead of the id? Try this xpath:
driver.find_element_by_xpath('//input[#class = "time hasTimepicker"]')
Try changing your xpath expression to
//input[starts-with(#id,"tp")]
or, if it's not always input
//*[starts-with(#id,"tp")]
To find the input element with that class use.
driver.find_element_by_css_selector("input.time.hasTimepicker")

what to do for dynamically changing xpaths in python using selenium?

I have a xpath as:
//*[#id="jobs-search-box-keyword-id-ember968"]
The number 968 constantly keeps on changing after every reload.
Rest of the string remains constant.
How to I find the constantly changing xpath?
You can use partial id with contains()
//*[contains(#id, "jobs-search-box-keyword-id-ember")]
You can try using starts-with below,
//*[starts-with(#id,'jobs-search-box-keyword-id-ember')]
The details provided is insufficient to to provide the accurate result. Still you can follow the below code references
In //*[#id="jobs-search-box-keyword-id-ember968"] the last number 968 keeps changing. but if you make this like //*[starts-with(#id,'jobs-search-box-keyword-id-ember')] then there might be possibility that you can have more then one element with the same partial is i.e. jobs-search-box-keyword-id-ember in this case it will locate on 1st matching element. that may not be your expected one
Use the tag name lets say element is an input tag whose id is jobs-search-box-keyword-id-ember968
Xpath - //input[starts-with(#id,'jobs-search-box-keyword-id-ember')]
CSS - input[id^='jobs-search-box-keyword-id-ember']
Use the relevant parent element to make this more specific. e.g the element is in parent tag <div class="container">
Xpath- //div[#class='container']//input[starts-with(#id,'jobs-search-box-keyword-id-ember')]
CSS - div.container input[id^='jobs-search-box-keyword-id-ember']
This worked for me:
Locator:
JOBS_SEARCH_BOX_XPATH = "//*[contains(#id,'jobs-search-box-keyword-id-ember')]"
Code:
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, JOBS_SEARCH_BOX_XPATH)))
.send_keys("SDET")

Python Selenium: Unable to click on a user name field

I am attempting to locate a user name field that does not have an ID or other locator that I can easily find using Selenium Web Driver.
Using Chrome's Inspect Element, the HTML for this object is as follows
<div aria-hidden="true" style="cursor:text" data-bind="text: hintText, css: hintCss" class="placeholder">someone#example.com</div>
What would be the best way to locate this page object?
Thanks
Either of these should work (if it is the first div-element of this class type)
driver.find_element_by_class_name('placeholder')
driver.find_element_by_css_selector('div.placeholder')
driver.find_element_by_xpath("//div[#class='placeholder']")
If there are more elements which match use the find_elements version of the methods and use the index of the returned list the get the element you need.
To click() the User Name field you can use either of the following line of code :
Using class and text attributes :
driver.findElement(By.xpath("//div[#class='placeholder' and contains(text(),'someone#example.com')]"));
Using class and aria-hidden attributes :
driver.findElement(By.xpath("//div[#class='placeholder' and #aria-hidden='true']"));
First find out is your element is inside different frame. Find the iframe, first switch to that, after which you will able to locate your user desired object by using any method like find_elemet_by_class_name or find_element_by_css_selector or by xpath.
For switching to frame try below code:
driver.switch_to.frame(driver.find_element_by_id("ID_OF_YOUR_FRAME"))
You can take the reference from this link code also for searching elements:
"https://github.com/PrajinkyaPimpalghare/TimeSheet-Automation/blob/master/time_sheet_automation.py" Refer from line 94 to 108 for accessing elements in different way and also in different frame.

Python Selenium using onclick

I am using selenium in python and cannot get it to find and select the ok button. Here is the code I am trying to use that is not finding the button.
SubmitElem = driver.find_element_by_name('ctl00$PlaceHolderMain$ctl01$RptControls$btnOK')
SubmitElem.submit()
And this is the webpage code
<input name="ctl00$PlaceHolderMain$ctl01$RptControls$btnOK"
value="OK"
onclick="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$PlaceHolderMain$ctl01$RptControls$btnOK", "", true, "", "", false, false))"
id="ctl00_PlaceHolderMain_ctl01_RptControls_btnOK" accesskey="o"
class="ms-ButtonHeightWidth" type="submit">
Any advice on what I am doing wrong? I found some suggestions to add onclick*= but it did not seem to work.
As noted earlier, if the element is in an iframe, you need to switch contexts. Additionally, if the element takes time to show up on the DOM, due to it being dynamically rendered by JavaScript, you might need waits. You basically want to wait until the element shows up on the page before performing actions on it.
From the Selenium docs:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
Here is the Answer to your Question:
As per the HTML you have provided, you may consider the following options:
You can consider to construct a xpath based on name as follows:
SubmitElem = driver.find_element_by_xpath("//input[#name='ctl00$PlaceHolderMain$ctl01$RptControls$btnOK']")
SubmitElem.submit()
You can also try a different xpath based on id as follows:
SubmitElem = driver.find_element_by_xpath("//input[#id='ctl00_PlaceHolderMain_ctl01_RptControls_btnOK']")
SubmitElem.submit()
Alternatively, you can also consider to call click() method instead of submit() method.
SubmitElem.click()
Again, it seems to me that the id and name is dynamic due to presence of JavaScript and AJAX Calls. In that case you can consider to construct a dynamic xpath as follows:
SubmitElem = driver.find_element_by_xpath("//input[starts-with(#id, 'ctl00')]")
SubmitElem.submit()
You can consider to construct a dynamic css_selector as follows:
SubmitElem = driver.find_element_by_css_selector("input[id^='ctl00']")
SubmitElem.submit()
Finally, if you see a NoSuchElementException or ElementNotVisibleException you may consider to induce some WebDriverWait as follows:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[starts-with(#name, 'ctl00')]")))
driver.find_element_by_css_selector("input[name^='ctl00']").click()
There are total 6 suggested locators to identify the element along with different other options.
Let me know if this Answers your Question.

Categories