Select the focused element in Selenium - python

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

Related

How do i find element in website that constanly change its label ID deep inside nested DIV?

I have a site that tracking all our shipment and i would like to use Selenium with Python to fetch all the value into my Excel file. But i'm currently stuck at getting Selenium to work. It will keep reporting back to me that the element is nowhere to be found. The element are also deep deep in the nested of DIV stuff.
at first i tried using
driver.find_element(By.XPATH,"//*[#id='trackItNowForm:j_idt529:0:j_idt535']").text
And quickly found out that part of the ID will constantly changing. (the "idt529:0:j_idt535" part in ID will constantly change to 519, 509 and so on. The zero path will also change based on lenght of data.) Without a clear structure. With that, By.ID is also obviously out of the window.
So now i'm currently out of idea on what to do next. Maybe i didn't put in the corrected syntax? I'm new to Selenium so i'm still confuse on a lot of things (like how XPATH are written and so on.) So an explanation will be appreciated.
You can locate that element by it's TrackingNumber class name. Maybe combined with more known attributes values.
Please try this:
driver.find_element(By.XPATH,"//label[contains(#id,'trackItNowForm') and(contains(#class,'TrackingNumber'))]").text
You may probably will need to add a delay to wait for the element to be visible. In this case WebDriverWait expected conditions is the right way to do it, as following:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(browser, 20)
wait.until(EC.visibility_of_element_located((By.XPATH, "//label[contains(#id,'trackItNowForm') and(contains(#class,'TrackingNumber'))]"))).text
You can try following css selector to identify the element.
option 1:
driver.find_element(By.CSS_SELECTOR,"[id^='trackItNowForm'][id*='id']").text
option 2:
driver.find_element(By.CSS_SELECTOR,"[id^='trackItNowForm'][id*='id'][class*='TrackingNumber']").text
where ^ means starts-with and * contains.
In option 1, it is checking id attribute starts-with trackItNowForm and also contains id
You should understand how xpath works.
For example, for the code you provided:
driver.find_element(By.XPATH,"//div[#class='col-sm-10']/label").text
looks for the first occurrence of a label under a div with the attribute class='col-sm-10' and then takes its text.
Useful links:
XPath syntax
XPath cheatsheet

Locating an element with no identifier in HTML using Selenium (Not using Xpath)

def page_nav(individual):
indiv_home = driver.find_element(By.XPATH, "/html/body/div/div[2] /div[2]/div[8]/a").click()
time.sleep(5)
person_select = driver.find_elemnet(By.TAG_NAME, individual).click()
<strong>Dylan Call</strong> <-- I want to find the element based off "Dylan Call"
The code above isn't the most well written and I know that (I'm fairly new my apologies in advance)
I'm looking for a way to find the element ("individual name") in the picture above since it doesn't have a unique identifier like "name" or "id".
I am attempting to create a bot that looks through a folder, identifies the name of the individual associated with a file, and uploads the file to that respective person's profile using selenium/python. Right now, I have stored the individual name in a variable, but I want to pass that variable through the "find_elements" function. Sadly I can't just use a "By.Xpath" to locate the element since I'm trying to find it specifically on the individual's name.
Does anyone have any workarounds or better ways to do this?
You can retrieve your strong tag containing individual name using an xpath as follow
individual = "Dylan Call"
driver.find_elements_by_xpath(f'//strong[#contains(text(), "{individual}")]')
Here // indicates that we are using relative xpath, this means we are looking for a strong tag anywhere in the html markup.
And we specify that the strong tag we are looking for has an innerText that contains the string given by variable individual.
May I suggest an improvement, you should not use time.sleep, but WebdriverWait in conjunction with ExpectedCondition. Instead of adding an arbitrary delay to wait until a page is loaded, this allow to wait until element we are trying to find is displayed.
All together you code becomes
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import presence_of_element_located
individual = "Dylan Call"
# create a wait object that will be used to wait at most 10 seconds that element appears.
wait = WebDriverWait(driver, 10)
# wait until the strong tag containing individual name appears.
# timeout if it did not appeared after 10 seconds.
person_select = wait.until(
presence_of_element_located((By.XPATH, f'//strong[#contains(text(), "{individual}"]'))
)
person_select.click()

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

Element is visible but cannot be found by webdriver

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.

How to select this button using Python and Selenium?

I am trying to use Python and Selenium to click either Yes or No on these buttons:
The HTML for these buttons is as follows:
I've tried to select based on the XPath:
isbnButton = browser.find_elements_by_xpath("//a[#data-toggle='haveisbn'")
as suggested by a friend, but it's giving me an error that says the string is not a valid XPath expression. I know pretty much nothing about XPath and am doing a tutorial right now while I await answers, but I'm hoping someone can guide me in the right direction.
What I originally tried was:
dontHaveISBN = driver.find_elements_by_class_name('btn radio btn-radio btn-primary not-active w-100')
dontHaveISBN[1].click()
but that wasn't recognizing any elements.
How would you select and click on these buttons?
You can give it a try with xpath again (try to copy exactly the xpath from the source code):
dontHaveISBN=driver.find_element_by_xpath('xpath_here')
dontHaveISBN.click()
You can try with this code :
wait = WebDriverWait(driver, 10)
yes_button = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, 'Yes')))
yes_button.click()
It's better to use Link Text than XPATH.
In case you want to use only xpath then that would be :
//a[text()='Yes']
Note that you will have to import these :
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
If you want to learn more about xpath then you can refer this link
Hope this will help.
In the xpath try you forgot the closing ], that's why it isn't valid. But there is a bigger issue with this locator: it matches the NO button as well.
In the class_name try you gave multiple classes as parameter, find_elements_by_class_name receives only one class as parameter.
data-id attribute seems to be unique, you can use it
# Yes button
driver.find_element_by_css_selector('[data-id="1"]')
# No button
driver.find_element_by_css_selector('[data-id="0"]')
# using xpath
driver.find_element_by_xpath('//a[#data-id="1"]')
Or using the text
driver.find_element_by_link_text('Yes')
driver.find_element_by_xpath('//a[text()="Yes"]')

Categories

Resources