Can I get specific "dl" i.e. at First or Second index out of many identified by a CSS Selector in my App - selenium

I'm trying to automate a functionality using selenium in my Application Chrome browser. It's an SVG graph based page and shows details upon mouse over it. And this is identifiable with a CSS selector which is returning more than one matching elements(i.e. 6-7 dl , these dls has few child tags then internally containing the values I need to verify -as attached), now my need to select them one by one at a time and verify text of them(which displayed on mouse over).
I got to know on google how to read nth-child from dl but not getting a way to select particular dl at first place.
For example-
my selector is: .d3-tip.n>dl
if I use -.d3-tip.n>dl>dt:nth-child(odd): its giving me all the attributes of dt.. ie 6 values but I nedd values only from fst dl.
Similarly.d3-tip.n>dl>dd:nth-child(even) returning the 6 values of respected dds..
In Actual my app has only one dl (on UI) but don't know why it displaying 6 in DOM...
Plz refer attachment and HTML for a clear understanding of DOM
<div class="d3-tip n" style="position: absolute; top: 44.5px; opacity: 0; pointer-events: none; box-sizing: border-box; left: 515px;">
<dl style="width:335px">
<dt>Space Name:</dt>
<dd>Space</dd>
<dt>Property Type:</dt>
<dd>Office</dd>
<dt>Quoted Area:</dt>
<dd>444 sf</dd>
<dt>Space Usage:</dt>
<dd>Business Park,Commercial School</dd>
<dt>Space Status:</dt>
<dd>For Lease</dd>
<dt>Possession Status:</dt>
<dd>Vacant</dd>
</dl>
<span class="d3-tip__pin"/>
</div>
<div class="d3-tip n" style="position: absolute; top: 44.5px; opacity: 0; pointer-events: none; box-sizing: border-box; left: 515px;">
<dl style="width:335px">
<dt>Space Name:</dt>
<dd>Space</dd>
<dt>Property Type:</dt>
<dd>Office</dd>
<dt>Quoted Area:</dt>
<dd>444 sf</dd>
<dt>Space Usage:</dt>
<dd>Business Park,Commercial School</dd>
<dt>Space Status:</dt>
<dd>For Lease</dd>
<dt>Possession Status:</dt>
<dd>Vacant</dd>
</dl>
<span class="d3-tip__pin"/>
</div>
<--! and so on up to 6 blocks of dl

nth-child is to find the nth-child of any immediate parent element. In your HTML DOM, dd is single child element of each div.d3-tip element. The repetitive child is actually your div.d3tip for it immediate parent element
So your selector has to be written as below to get the first set of dd,
div.d3-tip:nth-child(1)>dl>dd
Getting the second selector also works. This is most important while writing css selector. The second nth has to work. :).

Ok, so I am not sure which of the elements you want...
So... here is a snip that should give you help.
A) with hovering.
B) with looping through the elements.
C) Bonus learn about contains() functionality of XPath...
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
url = "http://your_url"
path_to_chromedriver = "C:\path_to_chromedriver"
chrome_options = Options()
#chrome_options.add_argument("--headless")
chrome_options.add_argument("--start-maximized")
browser = webdriver.Chrome(executable_path=path_to_chromedriver,
chrome_options=chrome_options)
browser.get(url)
# list_of_dt_elements_to_hover = browser.find_elements_by_xpath("//div[contains(#class,'d3-tip')]//dl/dt")
list_of_dt_elements_to_hover = browser.find_elements_by_xpath("//div[class='d3-tip n']//dl/dt")
list_of_dd_elements_to_hover = browser.find_elements_by_xpath("//div[contains(#class,'d3-tip')]//dl/dd")
hover = ActionChains(browser).move_to_element(list_of_dt_elements_to_hover[0])
hover.perform()
for dd_ele in list_of_dt_elements_to_hover:
hover = ActionChains(browser).move_to_element(dd_ele)
hover.perform()
print(dd_ele.text)
for dd_ele in list_of_dd_elements_to_hover:
hover = ActionChains(browser).move_to_element(dd_ele)
hover.perform()
print(dd_ele.text)
I hope you find this helpful!

Related

Dropdown List/Xpath Help (Selenium w/Python

I'm using Selenium with Python 3.5 to automate a process I do on a regular basis. However, I need to invoke a drop-down list by clicking a button on the header of the website. I've tried so many times to make this thing work but this is frustrating. I've tried to find the element by "ID","class", and directly copying the xpath into the code. I'm fairly new to this so any help is greatly appreciated! The truncated version of my code is:
SwitchOffices = driver.find_element_by_xpath('//*[#id="tdSwitchOff"]/a').click()
Here is the HTML code that I've highlighted on the selected item that will trigger the drop-down list:
<a class="BannerMessage" style="cursor: pointer; color: blue;
text-decoration: none;" onclick="JavaScript:fnShowBUList();"
onmouseout="this.style.textDecoration='none';"
onmouseover="this.style.textDecoration='underline';">
Switch Offices </a>
Not sure if this matters but this is the HTML code that is above the xpath that I want to put in my code.
<div id="tdSwitchOff" valign="top" style="float: right; visibility:
visible; display: inline;">
<a class="BannerMessage"
style="cursor: pointer; color: blue; text-decoration: none;"
onclick="JavaScript:fnShowBUList();" onmouseout="this.style.textDecoration='none';"
onmouseover="this.style.textDecoration='underline';">
Switch Offices </a> |
</div>
Running my Selenium code against the HTML provided produces a NoSuchElementException.
I don't see anything blatantly wrong with your XPath, but trying a different locator strategy never hurts -- you could try updating your locator to look directly for the a element, rather than going through the div first. I also invoke WebDriverWait so that we can ensure we are waiting for the element to exist before clicking it:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# wait for dropdown to exist
SwitchOffices = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//a[contains(text(), 'Switch Offices')]")))
# click dropdown
SwitchOffices.click()
If this does not work, there may be some other issues on the web page itself -- to further troubleshoot, we may need to see the full page HTML, or a link to the page you are automating.

Selenium - Unable to send text on the webpage which has hidden element

This is the webelement which is hidden in a page
<form method="post" action="" data-reactid="x.x.x.x">
<input class="barcode-input" data-reactid="x.x.x.x" type="text">
</form>
It doesn't have a hidden tag instead it is positioned # top: -9999px;
When i try this
driver.findElement(By.xpath("//input[#class='barcode-input'][#type='text']")).sendKeys("barcode123"+Keys.RETURN);
I get this
cause: org.openqa.selenium.ElementNotVisibleException, message: 'Element is not currently visible and so may not be interacted withCommand duration or timeout: 10.04
When tried to print the isDisplayed and isEnabled property for this element i get
isDisplayed = false,
isEnabled = true
The CSS style
input.barcode-input[type="text"] {
border-radius: 0 !important;
box-shadow: none !important;
outline: 0 none !important;
position: fixed;
top: -9999px;
transition: none 0s ease 0s !important;
}
If i disable the top css property which is shown above, i am able to see the text box. This is a webpage which is expecting user to scan a barcode and append "ENTER" keys to it.
Appending Enter keys i can use KEYS.RETURN.
But issue is with the actual text which needs to be passed to this element.
Actual page doesn't have a text box displayed on screen though since it expects user to scan barcode.
Is there a way to bring the element to focus and send keys to it?
First of all you have to change the value of type attribute as text from hidden. The following code using javascript would work for that:
jse.executeScript("document.getElementsByName('body')[0].setAttribute('type', 'text');");
Now, you are able to type on that text by using WebDriver. So, the overall code for typing with WebDriver using Java and Javascript as follows:
WebDriver driver = new FirefoxDriver();
JavascriptExecutor jse = (JavascriptExecutor)driver;
jse.executeScript("document.getElementsByName('body')[0].setAttribute('type', 'text');");
driver.findElement(By.xpath("//input[#name='body']")).clear();
driver.findElement(By.xpath("//input[#name='body']")).sendKeys("Ripon: body text");
Tried this and it resolved the issue
JavascriptExecutor javascript = (JavascriptExecutor) driver;
javascript.executeScript("document.getElementsByClassName(\"barcode-input\")[0].style.top=\"1\";");
javascript.executeScript("document.getElementsByClassName(\"barcode-input\")[0].value=\"test123\";");
driver.findElement(By.xpath("//input[#class='barcode-input']")).sendKeys(Keys.RETURN);

Dealing with Multiple Capybara React-select dropdowns?

So I have a page with multiple dropdowns (with the same choices) when automating a webpage using Capybara and Chromedriver.
They are all react-select's (Which I have a helper file for). Sadly they ALL have the same label text (but not label ID....however I don't think page.select works for label ID).
I thought about doing a page.all on the react-selects? and then just going through the array? Is that possible?
the react-select looks pretty standard, I realize the span has an id but selecting by that doesn't work for react-selects from what i've been able to tell.:
<div class="Select-control">
<span class="Select-multi-value-wrapper" id="react-select-6--value">
<div class="Select-placeholder">Select...</div>
<div class="Select-input" style="display: inline-block;">
<input role="combobox" aria-expanded="false" aria-owns="" aria-haspopup="false" aria-activedescendant="react-select-6--value" value="" style="width: 5px; box-sizing: content-box;">
<div style="position: absolute; top: 0px; left: 0px; visibility: hidden; height: 0px; overflow: scroll; white-space: pre;"></div>
</div>
</span>
<span class="Select-arrow-zone"><span class="Select-arrow"></span></span>
</div>
Could I maybe just pull it in via page.all? The react helper I have does this:
module CapybaraReactHelper
def capybara_react_select(selector, label)
within selector do
find('.Select-control').click
expect(page).to have_css('.Select-menu-outer') # options should now be available
expect(page).to have_css('.Select-option', text: label)
find('.Select-option', text: label).click
end
end
end
Any ideas?
Thanks!
Selecting by the id on .Select-multi-value-wrapper isn't working because that span isn't the react-select component's top-level tag. Working with react-select and Capybara generally is difficult because the Capybara form helpers won't work with react-select's custom markup and behavior.
As you've mentioned, you can get around this by using a version of your existing helper with a scoping within block and page.all(). For example:
# helper
def react_select_capybara(selector, option)
within selector do
find('.Select-arrow-zone').click
expect(page).to have_css('.Select-menu-outer')
find('.Select-option', text: option).click
expect(page).to have_css('.Select-value-label', text: option)
end
end
# usage
given(:select_values) { ['Grace Hopper', 'Ada Lovelace'] }
...
react_selects = page.all('.Select')
select_values.each do |select_value, i|
react_select_capybara(react_selects[i], select_value)
end
While this will work, it is brittle - it relies on the implicit ordering of your react-selects on the page. A more robust setup would pass each react-select component a custom classname to uniquely identify it in your test. From the react-select docs on custom classnames:
You can provide a custom className prop to the component, which will be added to the base .Select className for the outer container.
Implementing this might look like:
# JSX
<ReactSelect className="js-select-user-form-1" ... />
<ReactSelect className="js-select-user-form-2" ... />
# Spec
react_select_capybara(".js-select-user-form-1", 'Grace Hopper')
react_select_capybara(".js-select-user-form-2", 'Ada Lovelace')
page.select doesn't work for this because it only works for HTML <select> elements. This is a JS driven widget, not an HTML <select> element.
If you are just automating a page (not testing an app) it'll probably be easier just to use JS (via execute_script) to set the value of the hidden <input>s.
If you are testing an app, then you can use page.all to gather all the react-selects and step through, as long as selecting from any react-select doesn't replace any of the others on the page (which would leave you with obsolete elements).
If that doesn't provide enough info to solve your problem, and your real issue is trying to pick a specific react-select to select from, then please add enough HTML to your question so we can see what actual differences exist between the widgets you're trying to choose from (2 different react-select elements for instance)

element not visible: Element is not currently visible and may not be manipulated - Selenium webdriver

Following is the html
<div id="form1:customertype" class="ui-selectonemenu ui-widget ui-state-default ui-corner-all ui-state-hover" style="width: 165px;">
<div class="ui-helper-hidden-accessible">
<select id="form1:customertype_input" name="form1:customertype_input" tabindex="-1">
<option value="S">Staff</option>
<option value="C">Customer</option>
<option value="N">New To Bank</option></select></div>
<div class="ui-helper-hidden-accessible"><input id="form1:customertype_focus" name="form1:customertype_focus" type="text" readonly="readonly"></div>
<label id="form1:customertype_label" class="ui-selectonemenu-label ui-inputfield ui-corner-all" style="width: 149px;">Staff</label>
<div class="ui-selectonemenu-trigger ui-state-default ui-corner-right ui-state-hover"><span class="ui-icon ui-icon-triangle-1-s ui-c"></span></div></div>
The stylesheet of class="ui-helper-hidden-accessible" is
ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 0px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 0px;
}
Following is my code
WebElement customerType = driver.findElement(By.id("form1:customertype_input"));
Select select = new Select(customerType);
select.selectByVisibleText("New To Bank");
When I try to select "New to Bank" from the dropdown I get exception
element not visible: Element is not currently visible and may not be manipulated - Selenium webdriver
I have tried WebDriverWait technique but of no use, any ideas ?
I don't believe the text for that option is actually visible before you attempt to select it. Try selecting by value instead.
WebElement customerType = driver.findElement(By.id("form1:customertype_input"));
Select select = new Select(customerType);
select.selectByValue("N");
You may need to actually click the selector before being able to select an option, though.
WebElement customerType = driver.findElement(By.id("form1:customertype_input"));
new WebDriverWait(driver, 15).until(
ExpectedConditions.elementToBeClickable(customerType));
customerType.click();
Select select = new Select(customerType);
select.selectByValue("N");
try performing click on customerType before you create object of Select
Well, I found a work around to solve my problem but I am not happy with this. anyways what I did is focused on the div element that controls the dropdown by clicking it and and then sending down arrows keys twice followed by enter key. This selects my desired option. I used the following method
driver.switchTo().activeElement()
I also had the same problem and after hours I realized the browser was trying to click in a element before the page load.
So I create a sleep to solved the problem:
sleep(1)
P.S. - This is a solution that I really don't like.
I'm just pointing you the reason for that.
The best you can do is to check the page that you have the problem and try to optimize the load time.
I encounter the same problem. I have tried many methods.
Finally, the following python code solved the error.
I use javascript code to make the element visible before selecting the option.
css = 'select#state' # css selector of the element
js = """const data_options = Array.from(document.querySelectorAll('{css}'));
data_options.forEach(a=>{{a.style='display:block;';}});""".format(css=css)
self.driver.execute_script(js)
Maybe it's helpful for you!

Using javascript to set text for a web element - Selenium Web driver

How can text of a web element be set using java script executor? Or is there any other way to do this?
<a class="selectBox selectBox-dropdown selectBox-menuShowing selectBox-active" style="width: 52px; display: inline-block; -moz-user-select: none;" title="" tabindex="0">
<span class="selectBox-label" style="width: 13px;">10</span>
<span class="selectBox-arrow"/>
</a>
There are two span elements under the tag - which is a drop down. User clicks on span[2] and a list is shown which contains data like 10, 20, 30, 40, etc.. User clicks on the number(element) and that is set as the text of span[1] (In this case, 10 is selected). How should I go about solving this?
I tried Action builder and it is not working. Any others suggestions?
If you want to change the text of span[1] directly, you may use following code:
String jScript = "var myList = document.getElementsByClassName(\"selectBox-label\");"
+"myList[0].innerHTML=\"YourNumber\";";
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript(jScript);
However, you may also click the number using java script which as you say will set the text of span[1]. Example below:
WebElement element = driver.findElement(By.xpath("YourNumbersXpath"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);