Element is visible but cannot be found by webdriver - python

I'm using selenium and python for automated test and have an issue when try to click on an element in web.
I'm using find_element_by_xpath, provide the correct path (I have try on browser and it return 1 of 1).
driver = webdriver.Chrome()
driver.get('page_url')
driver.find_element_by_xpath(//button[#class="aoc-end md-button md-ink-ripple"])
Here is html:
<div class="_md md-open-menu-container md-whiteframe-z2 md-active md-clickable" id="menu_container_77" style="top: 499px; left: 866px; transform-origin: right top;" aria-hidden="false">
<md-menu-content class="agent-dropdown-menu-content new-menu-content" width="3" role="menu"><!----><md-menu-item>
<button class="aoc-end-work md-button md-ink-ripple" type="button" ng-transclude="" ng-disabled="!agent.capabilities.canSupervisorLogout" ng-click="logOutAgent(agent.userHandle)" role="menuitem">
The element should be found but actual result is that selenium.common.exceptions.ElementNotVisibleException: Message: element not visible

From the exception, it seems the element is present of the page but currently not visible.
Possible reason for invisibility of element can be (element is masked by another element, element can be in a drop - down list etc. ). If element is in drop-down list, then first open the list and then find the element.
Hope it will help.

Finding locators in web application developed in angular is quite tricky, especially when the developers don't follow any of guidelines useful from an automation perspective, like adding unique attributes for every web elements and etc...
In your case, it seems that the same thing is happening.
Following locator should work for you (by the way, you missed "" after and before locator in driver.find_element_by_xpath() method):
driver.find_element_by_xpath("//button[#ng-click='logOutAgent(agent.userHandle)']");

Since the element you are trying to click is a dynamic element, you will need to wait for it to become clickable before clicking on it. Use Expected conditions and WebDriver wait:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 20).until(
EC.element_to_be_clickable((By.XPATH, "//button[#class='aoc-end md-button md-ink-ripple']"))).click()
Also, notice the " " and ' ' quotes on the outer and inner xpath selector.

Related

Selecting Dynamic Element in Drop Down Menu, Selenium Python

I am trying to select an input box in a drop down menu. The input box itself, however, appears to be dynamic. I've looked through similar posts, but they seem to be issue specific. I've had this problem a few times now with dynamic elements, and I'm hoping to understand a general approach to working with dynamic elements.
Here are the details of the element I seek to select:
<input class="lui-search__input ng-pristine ng-valid ng-empty ng-valid-maxlength ng-touched" maxlength="5000" q-placeholder="Object.Listbox.Search" ng-model="query" ng-disabled="disabled" autocomplete="" spellcheck="false" ng-trim="false" type="text" qva-blur="blurred()" qva-focus="autoFocus" qv-escape="escape($event)" qv-enter="enter($event)" placeholder="Search in listbox" aria-invalid="false" xpath="1">
(if this isn't helpful information, please let me know and I will update).
The relative xpath changes:
//body/div[8]/div[1]/div[1]/div[1]/ng-transclude[1]/div[1]/div[3]/div[1]/article[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/input[1]
in one instance
Another instance of the relative xpath:
//body/div[7]/div[1]/div[1]/div[1]/ng-transclude[1]/div[1]/div[3]/div[1]/article[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/input[1]
I have tried to select by class and css selector with no luck. I'd really like to understand how to approach this specific issue, and also a general idea of where in an element I should play around with for future instances of dynamic elements.
Thanks!
(If the element details I provided are not helpful, the element can also be accessed with the below code:)
driver.get("https://bi.prozorro.org/sense/app/fba3f2f2-cf55-40a0-a79f-b74f5ce947c2/sheet/NFTrm/state/analysis")
driver.find_element_by_xpath("//thead/tr[1]/th[2]").click()
#the input box I am attempting to select to no avail:
while True:
try:
WebDriverWait(driver, 25).until(EC.presence_of_element_located((By.XPATH, "//body/div[7]/div[1]/div[1]/div[1]/ng-transclude[1]/div[1]/div[3]/div[1]/article[1]/div[1]/div[1]/div[1]/div[1]/div[1]/div[1]/input[1]")))
break
except TimeoutException:
print("Loading took too much time!")
The WebElement is an Angular element. So ideally to click on the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following Locator Strategies:
Using XPATH:
driver.get('https://bi.prozorro.org/sense/app/fba3f2f2-cf55-40a0-a79f-b74f5ce947c2/sheet/NFTrm/state/analysis')
WebDriverWait(driver, 60).until(EC.element_to_be_clickable((By.XPATH, "//th[#tid='st.header']//span[#title='Учасник']//following::th[#tid='st.header.search']"))).click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#placeholder='Search in listbox']"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
Browser Snapshot:
You can use one of it's attributes to find it.
XPATH:
//input[#placeholder='Search in listbox']

Python selenium cannot find element even with wait

I am trying to send text to an input field, but selenium is not able to find the element.
element = WebDriverWait(b, 10).until(EC.presence_of_element_located((By.XPATH, '/html/body/table/tbody/tr[1]/td/form/div/table/tbody/tr[2]/td/table[2]/tbody/tr/td[4]/table/tbody/tr/td[1]/input')))
element.send_keys("Customer Care", Keys.ENTER)
I've tried using the XPATH, the full XPATH and the ID to locate it, but it keeps giving me an error that indicates that it cannot find the element
selenium.common.exceptions.TimeoutException
A snippet of the HTML element
<input class="iceInpTxt testBox" id="headerForm:jumpto" maxlength="40" name="headerForm:jumpto" onblur="setFocus('');iceSubmitPartial(form, this, event);" onfocus="setFocus(this.id);" onkeyup="iceSubmit(form,this,event);" onmousedown="this.focus();" type="text" value="">
Element has ID, use it as locator. Check if element is inside a iframe:
wait = WebDriverWait(b, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'headerForm:jumpto')))
element.send_keys("Customer Care", Keys.ENTER)
How to switch to iframe:
wait = WebDriverWait(b, 10)
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe_locator")))
element = wait.until(EC.element_to_be_clickable((By.ID, 'headerForm:jumpto')))
element.send_keys("Customer Care", Keys.ENTER)
# How to go back to default content
b.switch_to.default_content()
it is a good idea to check whether or not you installed and imported selenium or other necessary packages. Use pip to check your version and see if there is a bug online. Please let me know what python version you are using. It is likely the XPATH you provided was incorrect or maybe try increasing the amount of time in the 2nd parameter of WebDriverWait(1st,2nd). It would be much more helpful if you had a link to this html page so I could check your XPATH. If you'd like further help, please provide your html page.
Edit:
This is something that needs to be reproduced so that it can be checked. If you have tried the above, I am unable to help unless I see the html document. You should remove all sensitive information before sharing it. The other elements of your code seem to be correct.
If your usecase involves invoking click() or send_keys() while inducing WebDriverWait instead of presence_of_element_located() you need to use the expected_conditions as element_to_be_clickable() as follows:
So effectively, you can use either of the following Locator Strategies:
Using CSS_SELECTOR:
WebDriverWait(b, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input.iceInpTxt.testBox[id^='headerForm'][name$='jumpto']"))).send_keys("Customer Care", Keys.ENTER)
Using XPATH:
WebDriverWait(b, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[#class='iceInpTxt testBox' and #id='headerForm:jumpto'][#name='headerForm:jumpto']"))).send_keys("Customer Care", Keys.ENTER)
References
You can find a couple of detailed discussion about the different expected_conditions in:
WebDriverWait not working as expected

How do i select a button from a table that has identical identifying selectors?

I'm trying to automate signing in on a page where there are two login buttons.
I'm still new with coding in general, but i read that xpath is the way to go.
browser.find_element_by_xpath("//input[#type='submit' and #value='Login']".click()
However, this defaults to the first login button. What selector should I use to select the second button?
This is the the code for the html:
Thanks
If the element more than one, you can use count [] at the end locator like this:
(//input[#type='submit' and #value='Login'])[2]
This is for second element:
browser.find_element_by_xpath("(//input[#type='submit' and #value='Login'])[2]").click()
Many ways you can do that.Since you are selecting last button.You can use index like (//input[#value='Login'])[last()]
Option 1:
browser.find_element_by_xpath("(//input[#value='Login'])[last()]").click()
Option 2
You can take the reference of table cell and xpath would be.
//td[#id='domainlogin_domain_selection']/following::td[1]/input[#value='Login']
So to click on the button.
browser.find_element_by_xpath("//td[#id='domainlogin_domain_selection']/following::td[1]/input[#value='Login']").click()
To handle dynamic element use WebDriverWait and element_to_be_clickable
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH,"//td[#id='domainlogin_domain_selection']/following::td[1]/input[#value='Login']"))).click()
OR
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH,"(//input[#value='Login'])[last()]"))).click()
Note : You need to import followings when you use WebDriverWait.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Consider using a css attribute = value selector with * contains operator to target the element by its onclick attribute. Nice and concise and easy to read
browser.find_element_by_css_selector("[onclick*=domainlogin]").click()
Reference:
Attribute selectors
Please try this code in order to click second login Button
browser.find_element_by_xpath("(//input[#value='Login'])[last()]").click()
or
browser.find_element_by_xpath("//td[#id='domainlogin_domain_selection']/following::td[1]/input[#value='Login']").click()
The buttons have different values of the onclick attribute so you can use the following selectors assuming using XPath contains() function:
First button:
//input[#type='submit' and #value='Login' and contains(#onclick, 'userLogin')]
Second button:
//input[#type='submit' and #value='Login' and contains(#onclick, 'domainLogin')]
References:
XPath Tutorial
XPath Axes
XPath Operators & Functions

Selenium can't find element of a link

I am trying to make a program which logs into my depop (A second-hand clothing selling app) and searches for a user. I've managed to make it log in so far. However, it can't find the element of the search button.
I've tried multiple didn't methods but none have worked. Keep in mind I have started learning this today so I am a beginner.
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys #allows keyboard to be used
from selenium.webdriver.common.by import By #allow waiting
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as cond
from selenium.webdriver.support import expected_conditions as ec
from selenium.common.exceptions import NoAlertPresentException
from selenium.common.exceptions import TimeoutException
def search():
driver.implicitly_wait(4)
searchbox = driver.find_element_by_name('a')
Message: no such element: Unable to locate element
I just get variations of this error message depending on how I do it.
EDIT:
The element is :
a
< span > Search < /span >
/a
EDIT 2: TO add some more detail onto this to make it easier to understand, when I click on the button, it makes a pull down menu of the actual search bar. So if it eventually finds the element. It gives me this "Message: stale element reference: element is not attached to the page document"
Your find_element_by_name function locates a WebElement by its name attribute, in your case neither span nor a tag have the name.
So you either need to go for find_element_by_tag_name attribute:
driver.find_element_by_tag_name("a")
but be aware that it will return the first link from the DOM, if you need to match the link having inner span with Search text you will need to go for XPath locator like:
driver.find_element_by_xpath("//span[contains(text(),'Search')]/parent::a")
It would be also good to wrap your locator into an Explicit Wait
a is not a name and hence it would not result in finding an element by using method find_element_by_name. Please try using xpath //span[text()='Search'] to find the element search. Please check(in developer console or some other browser extension like xpath, chropath etc) how many elements are being returned using this xpath. If there is just one element, you are good to go. Else, find some other strategy to reach to the desired element before proceeding with performing actions on it.

Select the focused element in Selenium

What I'm dealing with
In one of my tests I need to interact with a pop-up input field that is very hard to select using a regular css selector or xpath. I know, however, that this pop-up box will have the focus.
How can I use the fact that it's focused to properly assert that the input field contains some text?
Pseudocode of what I'm looking for:
element = driver.find_element_by_FIND_THE_ELEMENT_WITH_FOCUS
assert elem.text == "foobar"
Partial solutions I've come across:
Possibly a working solution in Ruby:
element = #driver.find_element :css, 'input:focus'
sleep(3)
element.send_keys "Hello WebDriver!"
assert_equal(element.attribute('value'),"Hello WebDriver!")
Getting the focused element with jQuery:
var focus = $(document.activeElement);
Could you provide a solution in python please?
EDIT:
Here's the HTML of the element:
<div class="css-1492t68">Select a speaker...</div>
I realized my question could've lead to some confusion as the element itself is does not have the semantic <input> tag but is rather a <div>. I suppose this is handled by the quill-editor library, which our dev team used when designing this app.
Here's a screenshot of the pop-up box:
Since the element does not have a consistent CSS class, using an XPath expression is probably going to be your best bet.
You need to wait for the element to be clickable (which means intractable) by matching a <div> that contains the expected text, and has a CSS class that begins with css-. Doing this should allow enough time for JavaScript to do its thing in the browser to initialize the quill-editor and display it:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ExpectedConditions
xpath = "//div[starts-with(#class, 'css-')][contains(., 'The text you expect to find')]"
expected_condition = ExpectedConditions.element_to_be_clickable((By.XPATH, xpath))
element = WebDriverWait(driver, 20).until(expected_condition)
If this pop up field is directly inside a particular parent element, you can further limit your xpath expression accordingly.
If this succeeds, no error will be thrown. If it does not succeed, it should throw a WebDriverTimeoutException (or whatever this error is called in Python).
use:
elem = driver.switch_to.active_element

Categories

Resources