Selenium getText does not work for an SVG xpath - selenium

I am trying to capture and store some text that appears inside of an svg element such as
<svg>
<g>
<text>Value to get</text>
</g>
</svg>
I have a method that I am using and it works for other elements, but the Selenium WebElement class method getText does not return any text for an svg element such as above.
Here is what my xpath looks like for the above example
//*[local-name()='g']//*[local-name()='text']
I am able to use findElement(By.xpath(myXpath)), but then when I call .getText() on it, it does not return any value and it also does not throw any errors.
Is there something I am doing wrong, or possibly an alternative method?
Also something interesting to note, the above approach worked fine on a Windows 7 machine, but not on Mac.

Have you tried something simple like a CSS selector, driver.findElement(By.cssSelector("svg > g > text")).getText();? Have you checked to see how many matches there are on the page? Perhaps the first match that you are getting actually has no text inside. Open the Chrome dev console and type $$("svg > g > text").length and see if it returns more than 1.
Here are some CSS selector references:
CSS Selectors Reference
CSS Selector Tips

Related

Karate UI: Locating text via CSS

I'm regularly hitting odd visible page text that karate cannot see, likely due to some funky JS magic that I don't fully understand.
Example image shows text on the page generated after clicking on a translate button:
I'm trying to assert that the translated text is present and correct on the page.
This is the selector:
#results-panel > div > div > div.thread > div > div.activity.panel.panel-default > div.panel-content > div > div:nth-child(2) > div:nth-child(1) > div > div.analysedText-translation > div > span:nth-child(3)
Example snippet of the element:
Using the wildcard {} or {^} doesn't work. eg waitFor('{^}A few random things about cats') returns a null
I played around with CSS selectors and am able to highlight the text using:
highlight('.analysedText-translation > div > span:nth-child(3)')[0]
I was thinking maybe using waitForText but not sure how to apply it. Any suggestions?
The reason the docs don't talk much about CSS selectors is that it is a standard. BTW this is open source, you are welcome to contribute pull-requests to improve the documentation.
UI automation is hard, I'm not going to claim that any framework makes it magically easier.
Suggestions:
if not already, start using the VS Code debugger, you can type things like highlight('div.panel-content') into the interactive console and play around with the page. see a video demo here (55:40) https://youtu.be/yu3uupBZyxc?t=3340
open the Chrome devtools console and type things like document.querySelector('div.panel-content') to see what gets matched
get a reference to any parent element and then you can "walk the tree": https://github.com/intuit/karate/tree/master/karate-core#tree-walking
If still stuck, follow this process so that we can fix anything in the framework if needed: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue

xpath: find element with attribute AND contains?

I am writing selenium tests, and I need to switch to an iframe with no id or name and which parent element contains variable id's (so not helpful. Also, the src attribute has variable data in it as well, so I can't target it directly like By.cssSelector("iframe[src='example']"). I need an xpath selector that targets the src, but also that uses contains. I am trying to learn how to build xpaths outside of Chrome's Copy XPath but I can't figure this one out. Thanks for your help! Here is the iframe html:
<iframe scrolling="auto"
src="/admin/catalog/manage_variants_in_product.jsp?productId=160502"
width="100%" height="100%" frameborder="no"
style="position:absolute; top:0px; left:0px;">
</iframe>
The "contains" CSS selector might help here:
iframe[src*=manage_variants_in_product]
FYI, there are also ^= and $= that mean "starts with" and "ends with" respectively.
The better way I would recommend to learn building xpath or csspath is Firepath add-on of Firefox
First install Firebug in your Firefox browse and then install Firepath.
There you will get the efficient way to get the xpath or evaluate the xpath build by yourself

selenium + capybara: find selector anywhere within element

Assume we have a <div class='whatever'> and somewhere deep inside there is an element <div class='inside-whatever'>
What i need is a way to access that particular inside-whatever-div using Capybara's and/or Selenium's methods.
Problem is, there is another <div class='inside-whatever'> on the page not inside <div class='whatever'>, so
within(:xpath,'//div[#class="whatever"]') do
find(:xpath,'//div[#class="inside-whatever"])
end
returns an error basically saying that there are multiple inside-whatever divs on the page.
What works is to build the xpath from whatever like
'//div[#class="whatever"]/div/div[3]/div/div[5]'
but that is pure madness.
So, is there any better way to look for selector anywhere inside any given element without having to specify a direct path?
You can merge your xpaths like this:
//div[#class="whatever"]//div[#class="inside-whatever"]
The real issue here is that you've fallen into the XPath // trap
find(:xpath,'//div[#class="inside-whatever"])
searches globally rather than from the context node. Instead you should get used to starting your XPaths with .// which will search from the current context node
within(:xpath,'.//div[#class="whatever"]') do
find(:xpath,'.//div[#class="inside-whatever"])
end
and do what you expect. This is mentioned in the Capybara README - https://github.com/teamcapybara/capybara#beware-the-xpath--trap
Note: CSS selectors don't have this issue and for most elements people are selecting read cleaner, which is why Capybara defaults to the :css selector
within('div.whatever') do
find('div.inside-whatever")
end

Selenium Webdriver Onlink Text

What command in webdriver should I use to make sure it clicks the specific text i.e Last Month
the code is
<div class="dt_padded_medium_div">
<a onclick="setLastMonth()" href="#">Last Month</a>
I tried xpath by using firepath but still doesnt work
it was
//*[#id='block-2']/div/div[3]/table/tbody/tr[1]/td[5]
I used
driver.findElement(By.xpath("//*[#id='block-2']/div/div[3]/table/tbody/tr[1]/td[5]")).click();
but still didnt work, am I missing something?
Update:
Got the Code working guys, thanks for the help!
If there is only one 'a' element in the page with this text, try this XPath:
//a[text()='Last Month']
If there are more than one element, please, post the full HTML tree else we're unable to write a xpath without know the tag path and ensure it will work
Are you sure your xPath is correct?
Install FirePath on Firefox and experiment with your xPath as on screenshot below.
Also, that does look like a long and brittle xPath. Look up xPath cheat sheets to learn how to make your xPath more robust.
In your case I would imagine something like:
//*[#id='block-2']/descendant::a[text()='Last Month']
(get the element with a particular ID, then search for an <a></a> in that element, no matter how deep, with a particular text)
In your question, you have used a "id" that is not shown in your code, where is #id='block-2'. It is possible for you to have used the wrong id. For us to help you, can you please provide the whole HTML code?
What I can suggest based on the information you have provided is:
Making sure the Xpath you have provided is unique, there is an add-on for Firefox called Firebug you can use. It will help you find out the xpath you are after fast and easy. What you need to do is basically:
download firefox and install it;
download firebug add-on and install it to firefox;
you will notice there is a small bug symbol to the top right of your tool bar, please enable it;
you will see a console pops out, click on inspection button and click on any web element you want to inspect and its html code will be highlighted in the console;
right click on the highlighted code and choose to copy its xpath to clipboard. This way you will never get your xpath wrong.
Here is a quick tutorial:
http://www.wikihow.com/Find-XPath-Using-Firebug
P.S. There are more than one way to locate a webelement, please consider using the following options as well:
Css selector
class name
id
This link will direct you to an awesome cheat cheet.
http://scraping.pro/res/xpath-cheat/xpath_css_dom_recipes.pdf
Hope it helps.
Please try to use below code to click on the text Last Month
driver.findElement(By.xpath(".//a[text()='Last Month']")).click();
Hope this helps.
You can use below code to click on the link containing the text 'Last Month'
driver.findElement(By.linkText("Last Month")).click();
First of all make sure that your xpath works correctly, try to use more specific xpath other than just td[5] or smthn like that, for example above could be like:
//div[#class='dt_padded_medium_div']/a[#href] - meaning, we need to find <div> element with specific parent and within it <a> element that has href property
There are a few possibilities.
If you're site doesn´t get rewritten to much you could just go for the link name via
driver.findElement(By.linkName("Last Month");
You could also go for any of the attributes if your site is subject of many rewrites like this and just put "href" and "#" or "onclick" and "setLastMonth()" as arguments when calling it.
static WebElement getLink(String Attribute, String Value /*String ItemText*/){
List<WebElement> Elements = driver.findElements(By.tagName("a"));
for(int Counter = 0, Counter < Elements.size(); Counter++){
if(Elements.get(Counter).getAttribute(Attribute).contains(Value) /* && Elements.get(Counter).getText().equals(ItemText){
return Elements.get(Counter);
}
}
return null;
}
If you remove the comments it will go completely sure and check for the Attributes and the displayed text.

Selecting element with multiple classes in Capybara

I'm writing automation code in Capybara with Selenium.
I have the following element in my HTML, and I wanna click this element in Capybara.
click me
At the moment, the way worked is something like following.
find('.classA', :text=>"click me").click
But I wanna select the element from the names of the two classes like this
find('a.classA.classB').click
click_on('a.classA.classB')
I know we can get javascript code fired, but this is not smart.
page.execute_script('$("a.classA.classB").click()')
You can search an element by xpath
based on your example, seems like the following should work
//div[contains(#class, 'classA') and contains(#class, 'classB')]
You could also use css
(:css, ".classA.classB")