Selenium Webdriver python: Element is not currently visible & same class name - python

I am using Selenium in python to click a button in a dialog. I try to click"OK", but it keeps getting errors
the buttons show "display:block" in CSS, cause "element is not visible" error
find_element_by_xpath, but the xpath of the element keeps changing
the class names are the same, how to choose the "OK" button?
Here are the code
<div<class="ui-dialog-buttonpane ui-widget-content ui-helper-clearfix">
<div<class="ui-dialog-buttonset">
<button type="button" class="large ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">Cancel</span>
</button>
<button type="button" class="orange large ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" role="button" aria-disabled="false">
<span class="ui-button-text">OK</span>
</button>
</div>
</div>
Thank you:)

If the element is invisible in the DOM like css { display: None}, {opacity: 0}... etc, , selenium will not be able to SEE it even given that you try to wait or time.sleep, instead you should use execute_script to run a JavaScript to trigger the desired event, something like this:
driver.execute_script('document.querySelector("span.ui-button-text").click();')

You should wait for the element to be ready before trying to click on it. Use waitForVisible or similar to achieve that.
For example, something like this:
element = WebDriverWait(driver, 10).until(
lambda driver : driver.find_element_by_xpath(element_xpath)
)
If the class remains the same, then you should select that class with element_xpath. The last thing you need to determine is what other attribute designates the button as ready. Then you can wait for the specific argument like:
def find(driver):
e = driver.find_element_by_xpath(element_xpath)
if (e.get_attribute(some_attribute)==some_value):
return False
return e
element = WebDriverWait(driver, 10).until(find)

Two different things can happen here.
• The selector is not explicitly returning the intended element
• Element load issue.
If both cases are true use explicit wait with a correct selector. In terms of selector I like using text bases search in such scenario. Notice I am using xpatth contains to make sure it eliminates any leading or tailing white spaces.
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH , "//span[contains(text(),'OK')]")))
API doc here

Related

How to click a Vue/Vuetify card using selenium in python?

I am using selenium version 4.0.0, for reference.
I'm trying to click a Vuetify card element, which is acting as a button, but I running into an element not interactable: [object HTMLDivElement] has no size and location or just element not interactable errors. I have been able to solve similar problems with action chains in the past, but it doesn't seem to work with this.
This is the list element the button is contained within:
<li class="lu-li list-item" data-v-711d8d7a="" style="display: flex;">
<div class="addCard v-card v-card--link v-sheet theme--light" data-v-711d8d7a="" tabindex="0" onselectstart="return false;">
::before
<i class="v-icon notranslate btnAdd material-icons theme--light enableIcon" data-v-711d8d7a="" aria-hidden="true">
add
::after
</i>
</div>
</li>
The first things I tried was simply clicking on the element, and then clicking on the <i> element beneath it when that didn't work:
addQLButton = driver.find_element(By.CLASS_NAME, "addCard")
addQLButton.click()
addQLButton = driver.find_element(By.CLASS_NAME, "btnAdd")
addQLButton.click()
I have already tried using WebDriverWait on both the v-card <div> and <i> element to make sure they are available before being clicked, which it passes without any issues:
WebDriverWait(driver, timeout=10).until(lambda d: d.find_element(By.CLASS_NAME, "addCard"))
WebDriverWait(driver, timeout=10).until(lambda d: d.find_element(By.CLASS_NAME, "btnAdd"))
I have already tried using action chains to make sure the elements are visible (this has worked in the past with similar errors), but I still run into the same issue:
addQLButton = driver.find_element(By.CLASS_NAME, "addCard")
actions.move_to_element(addQLButton).perform()
driver.execute_script("arguments[0].click();", addQLButton)
addQLButton = driver.find_element(By.CLASS_NAME, "btnAdd")
actions.move_to_element(addQLButton).perform()
driver.execute_script("arguments[0].click();", addQLButton)
The elements are not in an iframe, and I am sure I have the correct window selected as I am still able to interact with its elements.
I am at a bit of a loss, any help would be much appreciated. I'm happy to answer any clarifying questions if I didn't explain the issue clearly enough.
I managed to get it working with some javascript:
js = "document.querySelector('.btnAdd').click();"
driver.execute_script(js)

Finding/locating a clickable text by xpath in div/span format

I used the following line to click the Availability Grid button, but it failed to locate the element.
Class Sarsa-button-content is used everywhere so, I added text together to make it unique. However, it couldn't find it. What am I missing?
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='sarsa-button-content']/span[text()='Availability Grid']"))).click()
<div class="sticky-top-wrapper" style="top: 80px;">
<div class="site-filter-container" id="site-filter-container">
<a data-component="Button" class="sarsa-button view-by-availability-grid--button-tracker sarsa-button-primary sarsa-button-sm" href="/site/123456/availability">
<span class="sarsa-button-inner-wrapper">
<span class="sarsa-button-content">Availability Grid</span>
your xpath is wrong, try this:
//span[contains(#class, 'sarsa-button-content') and text() = 'Availability Grid']

Python/Selenium - Getting the element after an element

I need to close a popup window from the website itself by pressing the "X" window on the top right. Here is the shortened, relevant part of my code:
chromedriver = r'C:\Users\do\Desktop\chromedriver.exe'
browser = webdriver.Chrome(chromedriver)
url = 'Fake.com'
browser.get(url)
browser.find_element_by_id('imgAttachmentsImg').click()
# I need to close out the window after this
The issue is that there are no unique identifiers for the "X" button itself. However, the pop up itself does have a unique identifier. I just need to be able to flow it down to the X button.
Info from the page:
1. V<div class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-draggable ui-resizable" tabindex="-1" role="dialog" aria-describedby="attachmentsDialogOverview" aria-labelledby="ui-id-3" style="position: absolute; height: auto; width: auto; top: 239px; left: 102px; display: block;">
2. <div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix">
3. <span id="ui-id-3" class="ui-dialog-title">Attachments</span>
4. V<button type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only ui-dialog-titlebar-close" role="button" aria-disabled="false" title="close">
5. <span class="ui-button-icon-primary ui-icon ui-icon-closethick"</span>
6. <span class="ui-button-text">close</span></button>
I am new to using Python and Selenium. I switched over from VBA and still don't exactly understand all the syntax yet, so I do make mistakes! I did find a bandaid solution by just having sendkeys press Escape. But I am trying to actually understand how to actually solve this. I am not sure what errors I made with my solution:
browser.find_element_by_xpath("//span[#id, 'ui-id-3']/following-sibling::button").click()
Questions
Why did my solution not work?
How would I locate "ui-id-3"(on line 3) and get to the element on Line 4 to click it?
How would I locate "ui-id-3"(on line 3) and get to the element on Line 5 to click it? (just so I know how to move across multiple elements)
Relevant links I looked over:
Following-Sibling Python Selenium
Find next sibling element in Python Selenium?
Using XPath Selector 'following-sibling::text()' in Selenium (Python)
Python + Selenium WebDriver - Get div value if sibling contains string
What is the correct syntax for using a variable and following-sibling in Python Selenium?
The xpath has a problem. this should work:
browser.find_element_by_xpath("//span[#id='ui-id-3']/following-sibling::button").click()
To get to the span below it, you could use:
browser.find_element_by_xpath("//span[#id='ui-id-3']/following-sibling::button/span")
by the way, if you're more comfortable with CSS, the equivalent paths would be:
div#ui-id-3 > button
div#ui-id-3 > button span:nth-of-type(1)

Python-Selenium won't click button

The webpage i'm starting from is https://classschedule.tulane.edu/Search.aspx . The page source information for the button I need clicked is:
<input type="submit" name="ctl00$MainContent$btnSearchAll" value="All Courses" id="btnSearchAll" class="JQButton ui-button ui-widget ui-state-default ui-corner-all" role="button" aria-disabled="false" autocomplete="off" style="height: 22px;">
I have tried different methods to find this button and click on it such as;
element = browser.find_element_by_id("btnSearchAll")
element = browser.find_element_by_xpath("//input[#id ='btnSearchAll']")
element = browser.find_element_by_name("ctl00$MainContent$btnSearchAll")
I think it is finding the button because when I do...
print element
...this is returned:
<selenium.webdriver.remote.webelement.WebElement object at 0x2b49690>
I have no other ideas on how to make my program click the button.
I think you didn't add the code for clicking on the element. Please do that and check:
element = browser.find_element_by_id("btnSearchAll")
element.click()
I did try the same code as above with JAVA, and it is working fine.
This works well for me
for i in range(1, 10):
try:
driver.find_element_by_xpath(
f'/html/body/div[{i}]/div/div/div/div/div[2]/span[1]/span/span/input').click()
except:
pass

Selenium: Timing inconsistency with WebDriverWait & click

I have a set of divs to show/hide content in a typical accordion style. The HTML looks like this;
<div class="accordionContainer">
<div class="accordion">
<h3>Click This</h3>
<div class="accordionContent" style="display:none">
</div>
</div>
<div class="accordion">
<h3>Click This</h3>
<div class="accordionContent" style="display:none">
</div>
</div>
</div>
I've then got my python to select that first H3 and then open a link that is in accordionContent.
WebDriverWait(ff, 10).until(lambda driver : driver.find_element_by_xpath("id('main_content')/div[3]/div/div/div[1]/h3[1]")).click()
WebDriverWait(ff, 10).until(lambda driver : driver.find_element_by_xpath("id('main_content')/div[3]/div/div/div[1]/div/p/a")).click()
I have ran this & seen it work. However most of the time it fails. The first div gets clicked (I can see a little arrow on it rotate to show the content but it seems to get clicked twice as it immediately returns to default and I get the error;
[exec] selenium.common.exceptions.ElementNotVisibleException: Message: u'Element is not currently visible and so may not be interacted with'
Oddly though when it can be seen to be clicked, but not open, if you call the same click() line a second time it works.
Can that second xpath be advanced to check that the accordionContent has been changed to display: block?
This xpath should work:
"//div[#class='accordionContainer']/div[#class='accordion'][1]/div[#class='accordionContent' and contains(#style, 'block')]"
or if the structure is pretty safe, could do:
"//div[#class='accordionContainer']/div[1]/div[contains(#style, 'block')]"
Note: I am assuming that it is just a typo in the example that the closing tag for the 'accordion' div is supposed to be a closing tag (rather than the opening tag seen).

Categories