How to select button inside of multiple classes with selenium python? - python

I have a page with multiple elements, it's called cards, and on this page I want to click a button on some cards but not on all. The problem is the structure of individual cards because only class of card is different but class inside of cards and button are the same. I'm not sure how to find a right card.
Usually I use something like this, but in this case i want to select certain cards.
browser.find_element(By.CLASS_NAME, 'button-class').click()
But in this case I have something like this...
<div id="card-summer_1">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
<div id="card-summer_2">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
<div id="card-summer_3">
<div class="card_card">
<div class="card_footer">
<button class="button-class">
<button class="button-share">
</button>
</div>
</div>
</div>
How to click on button on id id="card-summer_1" and id="card-summer_3"?
Thanks in advance!
EDIT
There are two buttons, I want to click on a class button-class.

Find elements instead by CSS selector:
driver.find_element(By.CSS_SELECTOR, ".card-summer_1 .button-class")

By XPATH:
driver.find_element(By.XPATH, "//div[#id='card-summer_1']//button"]).click()
driver.find_element(By.XPATH, "//div[#id='card-summer_3']//button"]).click()
By CSS_SELECTOR:
driver.find_element(By.By.CSS_SELECTOR, ".card-summer_1 button").click()
driver.find_element(By.By.CSS_SELECTOR, ".card-summer_3 button").click()

Related

Cannot find element in selenium python?

I am trying to navigate to a search box and send_keys with selenium python but completely stuck.
And here is the source code snippet:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<div id="LeftTreeFrame" class="leftNavBackground" >
<div class="ui-widget searchPanelContainer">
<div id="searchPanel" class="search-field-container search-field-container-margin">
<input type="text" doesntDirty id="Search" name="Search" class="search-text-field-left-tree-frame" NoHighlight="nohighlight"/>
<div class="search-field-icon-container">
<a id="searchlbl" href="#"><img src="../images/normal_search_u39.svg" title="Go To Page" /></a>
</div>
</div>
</div>
<div id='pageNavigation'>
<div id='ootbNavigationPage'></div>
<div id='favoriteNavigationPage'></div>
<div id='adminNavigationPage'></div>
<div id='navigationEmptyState' class="treeEmptyState">
<div class="message"></div>
</div>
</div>
<div class="navigation-view-mode-container">
<div class="box" onclick="renderModel(0)">
<button type="button">
<span class="svg-load ootb-icon" data-src="~/images/Reskin/ootb-icon.svg"></span>
</button>
</div>
<div class="star" onclick="renderModel(1)">
<button type="button">
<span class="svg-load star-icon" data-src="~/images/Reskin/star.svg"></span>
</button>
</div>
<div class="person" onclick="renderModel(2)">
<button type="button">
<span class="svg-load person-icon" data-src="~/images/Reskin/person-nav.svg"></span>
</button>
</div>
</div>
</div>
When I try to do
element = driver.find_element(By.XPATH, '//input[#name="Search"]')
element.send_keys('test')
I get error "selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable"
I have tried everything I can imagine, but cannot click the element or send keys.
Also, this page is a new page that opens after the last successful click. I first tried switching to this page by
#printing handles
handles = driver.window_handles
i=0
for handle in handles:
print(f"Handle {i}: {handle}\n")
i +=1
#after confirming new page is second handle via:
driver.switch_to.window(handles[1])
print(f" Title: {driver.title}")
print(f" Current url: {driver.current_url}")
print('\n')
#I can even find the tag I am looking for after switching to new window:
all_div_tags = driver.find_elements(By.TAG_NAME, "input")
for tag in all_div_tags:
print(f"Attribute name: {tag.get_attribute('name')}\n")
#but i cannot get to the search box. Thank you in advance!
Look at the html code, notice that //input[#name="Search"] is contained in an <iframe>. In order to select an element inside an iframe with find_element() you have first to switch to the iframe, as shown in the code
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.ID, "frmCode")))
element = driver.find_element(By.XPATH, '//input[#name="Search"]')
...

I am trying to click on a button which has the following html structure: Not able to click the button "English". It says no such element. Tried Xpath

Could not click the button English.
It says no such element exists.
Tried the following and Select method.
element = WebDriverWait(driver, 40).until(expected_conditions.element_to_be_clickable((By.XPATH, "/html/body/content/main/div/form")))
select = Select(driver.find_element_by_css_selector("label[for='language-MCQ'] span[class='me-2']"))
Code block:
<input class="form-check-input d-none lang-list" type="checkbox" id="language-MCQ" name="language_ids[]" value="1" wire:model="language_ids.0" wire:change="addLanguageQuestions(1)">
<label class="form-check-label d-flex flex-nowrap align-items-center rounded-pill btn btn-lg btn-lang-select text-white cursor-pointer" for="language-MCQ">
<span class="me-2">
English
</span>
</label>
<div class="form-check ps-0 me-3">
<input class="form-check-input d-none lang-list" type="checkbox" id="language-Kannada" name="language_ids[]" value="2" wire:model="language_ids.1" wire:change="addLanguageQuestions(2)">
<label class="form-check-label d-flex flex-nowrap align-items-center rounded-pill btn btn-lg btn-lang-select text-white cursor-pointer" for="language-Kannada">
<span class="me-2">
Kannada
</span>
</label>
</div>
Did you try this xpath :
//span[text()='English']
if you do not wish to use text()
//label[#for='language-MCQ']/span
also this looks wrong
select = Select(driver.find_element_by_css_selector("label[for='language-MCQ'] span[class='me-2']"))
Note that Select is only applicable for html select tag.
To minimize the possibility of any kind of exception it is recommended that your xpath should be pointed to the interactive element, In this case span or label is not interactive element but the input tag.
and your possible xpath solutions can be -
.//span[contains(text(),'English')]/ancestor::label/preceding-sibling::input
Or
.//input[#id='language-MCQ']
Or
.//label[contains(#class,'btn-lang-select')]/preceding-sibling::input[#value='1']
something like this should work -
element = WebDriverWait(driver, 40).until(expected_conditions.element_to_be_clickable((By.XPATH, ".//span[contains(text(),'English')]/ancestor::label/preceding-sibling::input")))
element.click()
If the above xpaths are not working with the explicit wait and expected conditions then check element should be in iframe.

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.

Selenium clicking buttons by traversing through parent node

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()

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)

Categories