Selenium: Timing inconsistency with WebDriverWait & click - python

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

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 - Find element by label text

Im trying to locate and click an element (checkbox) from a big selection of checkboxes on a html site using python and selenium webdriver. HTML code looks like this:
HTML Code
<div class="checkbox-inline col-md-5 col-lg-3 col-sm-6 m-l-sm rightCheckBox">
<input type="checkbox" checked="checked" class="i-checks" name="PanelsContainer:tabsContentView:5:listTabs:rights-group-container:right-type-view:2:right-view:2:affected-right" disabled="disabled" id="id199"> <label>Delete group</label>
</div>
My problem is that the only unique identifier is:
<label>Delete group</label>
All other elements/id's/names are used by other checkboxes or changes from page to page.
I have tried the following code:
driver.find_element_by_xpath("//label[contains(text(), 'Delete group')]").click()
But I only get error when using this.
Error: element not interactable
Anyone able to help with this?
Try the below xpath
//label[contains(text(), 'Delete group')]//ancestor::div//input
Try with Javascript.
checkBox = driver.find_element_by_xpath("//label[text()='Delete group']//ancestor::div//input")
# Scroll to checkbox if its not in screen
driver.execute_script("arguments[0].scrollIntoView();", checkBox)
driver.execute_script("arguments[0].click();", checkBox)
Note : As per HTML shared by you, checkbox is in Disabled state, so i am not sure click will trigger any action. However above code will click your checkbox.

Python Selenium: clicking a "visible" element using Selenium gives me an "element not visible" error

I am trying to test against this website. (https://www.phptravels.net/), and I want to test its Login feature. There is a "My Account" link, which needs to be clicked first to show the drop down of the Login and Sign up button. The HTML code is like this:
<li id="li_myaccount" class="">
<span class="ink animate" style="height: 137px; width: 137px; top: -10.7969px; left: -28.7344px;"></span><i class="icon_set_1_icon-70 go-right"></i> My Account <b class="lightcaret mt-2 go-left"></b>
<ul class="dropdown-menu">
<li><a class="go-text-right" href="https://www.phptravels.net/login"> Login</a></li>
<li><a class="go-text-right" href="https://www.phptravels.net/register"> Sign Up</a></li>
</ul>
</li>
When I try to click the "My Account" button, it throws an error msg saying "element not visible". I am confused because apparently this button is visible all the time. Here is the code:
elem = driver.find_element_by_xpath("//*[#id='li_myaccount']/a")
elem.click()
What is wrong with my code? Thank you.
I tried to interact with the My Account Link, which is shown in the right part of the navigation bar on the page (https://www.phptravels.net/). Using the locator //*[#id='li_myaccount']/a when I try to click the Link, using the Webdriver, I get the below error:
ElementNotVisibleException: Message: element not interactable
When I explored the html using Chrome's console and searched the element using the locator //*[#id='li_myaccount']/a, the My Account Link, which you want to click doesn't get highlighted.
Therefore further exploration led me to choose the locator //*[contains(#class,'navbar-nav navbar-right')]//*[#id='li_myaccount']/a which highlights the My Account Link.
Then I used the new locator to click My Account link, using the Webdriver and it works !
If you notice carefully, I just added preceding path in the locator that you shared to uniquely identify the My Account Link.
Change the xpath to this one:
(//*[#id='li_myaccount']/a)[2]
If you look at the source, there are actually 2 elements matching this locator - an <a> tag in some modal that's currently hidden, and the one you are trying to address; thus your issue, the method returns the first one, which is not the desired.
This xpath will return the 2nd element ([2]) from the set of responses (the () surrounding the looked-for value).

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

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

Categories