Selenium clicking buttons by traversing through parent node - python

Need to exercise buttons ( edit / delete) in following HTML. Unique between all devices are "device-name". Hence locating target device is straight as -
cmd = "//div[#class='device-name' and text()='%s']" % (devicename)
element = brHandle.find_elements_by_xpath(cmd)
HTML -
<div class="device" id="device-1">..</div>
<div class="device" id="device-2">..</div>
<div class="device-form-factor desktop">
<div class="device-platform unknown"></div>
<div class="device-status">
....
</div>
</div>
<div class="device-name">auto-generated</div>
<div class="buttons">
<div class="button edit" href="#">Edit</div>
<div class="button delete" href="#">Delete</div>
</div>
</div>
<div class="device" id="device-3">..</div>
....
To access parent and then button, i tried following- but didn't work out. I was expecting to fetch device-id and then form my xpath to edit/delete button. Please suggest -
parent = element.find_element_by_xpath("..").text()

Related

Selenium clicking a specific button object from a list of objects with python

I am grabbing a list of buttons, then I am attempting to click a specific button object, I collect all buttons (which contain details such as a name). I check the name, if I have already clicked on this button, pass, or else click this button object.
The problem I am having is that the button doesn't have an ID so I am unsure of how to dynamically identify the button to click it (from the object in the loop). It doesn't have an HREF either.
If it had an ID, I could grab the ID value and build a selenium click even such as browser.find_element(By.ID, "button-ID").click().
Any pointers would be appreciated.
html = browser.page_source
soup = BeautifulSoup(html, "lxml")
buttons = soup.find_all('button', {'class', 'full-width'})
for button in buttons:
button_soup = BeautifulSoup(str(button), 'lxml')
name_div = button_soup.find('div', {'class': 'artdeco-entity-lockup__title'})
name = name_div.find('span', {'aria-hidden': 'true'}).text
if name in lead_check:
pass
else:
"""HERE IS WHERE I NEED TO CLICK THE BUTTON OBJECT"""
browser.find_element(By.CSS_SELECTOR, "button.full-width").click()
Button Object (one button from loop) example
<button class="full-width member-analytics-addon__cta-list-item-content member-analytics-addon-entity-list__link member-analytics-addon-entity-list__link--no-underline-hover" role="button" type="button">
<div class="member-analytics-addon-entity-list__entity artdeco-entity-lockup artdeco-entity-lockup--size-3 ember-view" id="112">
<div class="artdeco-entity-lockup__image artdeco-entity-lockup__image--type-circle ember-view" id="113" type="circle">
<div class="ivm-image-view-model">
<div class="ivm-view-attr__img-wrapper ivm-view-attr__img-wrapper--use-img-tag display-flex">
<!-- --> <img alt="" class="ivm-view-attr__img--centered EntityPhoto-circle-3 EntityPhoto-circle-3 lazy-image ember-view" height="48" id="114" loading="lazy" src="linktopic" width="48"/>
</div>
</div>
<!-- -->
</div>
<div class="artdeco-entity-lockup__content ember-view member-analytics-addon-entity-list__entity-content" id="115">
<div>
<div class="artdeco-entity-lockup__title ember-view member-analytics-addon-entity-list__entity-content-title" id="116">
<span dir="ltr"><span aria-hidden="true"><!-- -->John Smith<!-- --></span><span class="visually-hidden"><!-- -->View Johns’s profile<!-- --></span></span>
</div>
<div class="artdeco-entity-lockup__badge ember-view t-normal" id="117"><!-- --> <span aria-hidden="false" class="artdeco-entity-lockup__degree">
· 3rd
</span>
<!-- --><!-- --></div>
<div class="artdeco-entity-lockup__subtitle ember-view" id="118">
<!-- -->Loves cats<!-- -->
</div>
<!-- --> </div>
<!-- --> </div>
</div>
</button>
I solved this by identifying a unique variable in each button, in this instance an IMG URL then dynamically located each with selenium.
img_src = button_soup.find('img')['src']
path_location = "//img[contains(#src,'{}')]".format(img_src)
browser.find_element(By.XPATH, path_location).click()

XPATH help - finding text, then the following button a few divs later

XPATH newbie... I am trying to find text, then find the following button in a code block like below.
The ember numbers change so can't use those. Need to find text within a span, then the next (following) button after that text is found. Then click on that button. In this case it's a contact button.
I've tried:
//*[text()[contains(.,'Jason')]]/div/div/button
Also tried:
//*[text()[contains(.,'Jason')]]/following-sibling::button
A code block example I am trying to search.
<div data-test="e-list-item" data-e-id="Fdh348uF" class="material-list-tile e-list-item">
<div class="e-name">
<a href="/embed/Gdfsdjfhd25d88/gallery/Fdh348uF" id="ember2539" class="ember-view"> <span data-test="e-name">Jason Alamoa</span>
</a><!----> </div>
<!----> <div id="ember2539" class="c-info ember-view"> <div class="c-icons">
<!---->
<!---->
<!---->
<!---->
</div>
</div>
<div class="e-actions">
<div class="e-action-buttons">
<!----> <div class="e-action">
<button class="ssButton ssButtonPrimary v-button v " type="button" data-ember-action="" data-ember-action-2540="2540">
<i class="ssIcon-ok-sign ssIcon-large"></i>
Contact
</button>
<!---->
</div>
</div>
</div>
</div>
Based on HTML snippet provided following XPath could be used:
//div[./a/span[contains(.,'Jason')]]/following::div[#class="e-actions"]//button
Explanation:
//div[./a/span[contains(.,'Jason')]] => selects "div" with child "a" containing child "span" containing text "Jason"
/following::div[#class="e-actions"] => selects following "div" after the first one having attribute "class" with value "e-actions"
//button => selects "button" inside of the previous "div"
If you want to find span with specific text and following button, the easiest way
//span[contains(text(), 'Jason')]/following::button

Selenium WebDriver Exceptions - "element not interact-able"

I am trying to select elements from a drop down box, which loads options once clicked. I can get to the element but not interact with it. The error is NOT due to the page not fully loading as most related questions are.
I've tried selecting element by Id, Xpath, and using the js to make the element not hidden, none have worked so far. the latest i've tried was to send the keys.down to activate the list... still get the "not interactable" error.
Web page with selector--
</div>
</div>
<div class="css-1wy0on6 av__indicators">
<span class="css-bgvzuu-indicatorSeparator av__indicator-separator">
</span>
<div aria-hidden="true" class="css-1u02eyf-indicatorContainer av__indicator av__dropdown-indicator">
<svg aria-hidden="true" class="css-19bqh2r" focusable="false" height="20" viewbox="0 0 20 20" width="20">
<path d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z">
</path>
</svg>
<span class="sr-only">
Toggle Select Options
</span>
</div>
</div>
</div>
<input name="organization" type="hidden" value="" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-md-10 col-lg-8">
</div>
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary disabled" disabled="" type="submit">
Continue
</button>
</div>
</div>
</form>
</div>
</div>
Some Python code used so far--
elem = driver.find_element_by_name("organization")
js = "arguments[0].style.height='auto';
arguments[0].style.visibility='visible';"
driver.execute_script(js, elem)
from selenium.webdriver.common.keys import Keys
elem.send_keys(Keys.DOWN)
###not interactable Error
I would expect the item to allow me to select or activate the options list at the least. I have been successful in lists, but not this new type.
The INPUT you are trying to interact with is of type="hidden" so it won't be visible and can't be interacted with using Selenium. My guess is that there's a dropdown that isn't a SELECT that is displayed, the user makes a selection, and then code pushes that value into the hidden INPUT. Just ignore the hidden INPUT and interact with the page as a user would by clicking the dropdown, then clicking your selection. The rest should take care of itself.
We can't make more recommendations on locators, etc. without more of the HTML of the page since you stated that the site is behind an account.

How to verify dynamic element present in Selenium WebDriver

I'm writing scripts in Python using Selenium WebDriver to test a web application.
The web application allows users to ask questions, which are added to a div as they are asked. Each question div has their own "upvote" and "downvote" link/image. The image changes when the "upvote" icon is clicked, from active to inactive, or vice versa. I know that the xpath to this upvote icon is:
"//div[#id='recent-questions-container']/div/div/div/div/div[2]/div/ul/li/a/i"
This "i" at the end of the path is a class, and will either be
<i class="fa fa-2x fa-thumbs-o-up"></i>
or
<i class="fa fa-2x fa-thumbs-up clicked"></i>
depending on whether or not it is clicked. I want to verify that the correct image is in place upon being clicked. How can I do that? Ideally, I'd like to perform this verification using assertions, a la:
self.assertTrue(self.is_element_present( ... ))
Here is the html for what I'm talking about
<div id="recent-questions-container">
<div question_id="randomly generated blah" class="q row recent-question animated pulse" data-score="0">
<div class="col-xs-12">
<div class="question-content">
<p>3</p>
<div class="row question-controls">
<div class="owner-view hidden">
...
<div class="student-view">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 question-controls-left">
<ul class="list-inline">
<li>
<a href="#" class="student-view thumbs-up-to-active">
<i class="fa fa-thumbs-o-up fa-2x"></i></a>
</li>
<li>
<span class="num-votes">0</span>
</li>
<li class="thumbs-down-li">
<a href="#" class="student-view thumbs-down-to-active">
<i class="fa fa-thumbs-o-down fa-2x"></i></a>
</li>
</ul>
</div>
</div>
</div>
<hr>
</div>
</div>
</div>
... other questions ...
</div>
<hr>
</div>
</div>
</div>
</div>
You can use get_attribute to get the class attribute and then do a search if the class contains clicked to make sure it was in fact clicked
#make sure the selector is correct
xpath = "//div[#id='recent-questions-container']/div/div/div/div/div[2]/div/ul/li/a/i"
element = driver.find_element(By.XPATH, xpath)
attr = element.get_attribute('class')
if 'clicked' in attr:
print("clicked")
else:
print("was not clicked")
Edit
I would click the element and now should be expecting to change the class to active. Then find the count which should be more than 0
driver = self.driver
#perform click here
#the idea is to avoid the NoSuchElement exception
# and see if the element count is greater than 0
assert (len(driver.find_elements_by_css_selector(".student-view.thumbs-up-to-active")) > 0)

Follow a sibling in Selenium/Python

I want to enter a text in a text area. The HTML code is as follows:
<li class="order-unavailable string-type-key string-block clear-fix status- require_changes expanded working autogrowed activity-opened" data-string_status="require_changes" data-master_unit_count="22" data-string_id="2394473">
<div class="key-area clear-fix">
<div class="key-area-container-one clear-fix">
<div class="key-area-container-two">
<div class="col-50 col-left">
<div class="string-controls">
<a class="control-expand-toggle selected" href="#"></a>
<a class="control-activity-toggle " href="#">2</a>
<input class="control-select-string" type="checkbox">
</div>
<div class="master-content">
</div>
<div class="col-50 col-right slave-side-container">
</div>
</div>
</div>
<div class="activity-area clear-fix">
<div class="col-50 col-left">
<div class="col-50 col-right">
<div class="comment-area-inner">
<h3>Add comment</h3>
<div class="comment-container">
<textarea class="comment-content" name="comment_content"></textarea>
</div>
<div class="col-right">
<div class="clear"></div>
<strong>Notification settings</strong>
<p>The people you select will get an email when you post this comment. They'll also be notified by email every time a new comment is added.</p>
<div class="notification-settings">
</div>
</div>
</div>
The textarea component name is comment-content
The xpath of the textarea is:
/html/body/div/section/ol/li[16]/div[2]/div[2]/div/div/textarea
This is the code I am using:
driver.find_element_by_xpath("*//div[#title=\"NOTIFICATION_HOMEPAGE_REDIRECT_CHANGED_SITE\"]
/following-sibling::div[2]/div[2]/div/div/textarea").send_keys("Test comment")
Can someone hekp me how to frame the sibling tag?
div[2]/div[2]/div/div/textarea
The tag before the following-sibling keyword is correct.
Choose the textarea and enter something,
driver.find_element_by_xpath(r'//textarea[#class='comment-content']').send_keys('Test Comment')
For xpath, you can use tool Firepath plugin for Firefox

Categories