I testautomated a small part of Outlook Web App. Here I check a test mailbox that our company sends emails to. Within a certain email there are texts I want to check by using Assert. The problem is that I have difficulties finding the right xpath. The HTML looks like this:
<div align="left">
<font size="2" face="Tahoma">
<br>
Wij hebben uw bouwdepotdeclaratie verwerkt.
</font>
<br>
</div>
To use driver.findElement(By.xpath(xpath)) I used the following xpath first:
//font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]/br, but that gives me just the <br> tag.
Afther that I tried //font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]/text() and that seemed to give me the xpath that I wanted, because in element inspector it highlighted the text Wij hebben uw bouwdepotdeclaratie verwerkt. That is the actual text that I want the selenium webdriver to find and use to store (with .getText()) in a String. But when I used that with driver.findElement(By.xpath(xpath)).getText() it gave me a NoSuchElementException.
What did I do wrong? What would be the right xpath that I can use with the webdriver to get the text?
The way your HTML is set up and given what you want, you want to get the FONT tag. In your first XPath you are pulling the BR tag, which is why it didn't work. Your second XPath is using text() which, if I remember correctly, isn't supported by Selenium. The easier way is to modify your first XPath to just get the FONT tag (just remove /br).
//font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]
Using this XPath, the code below should work.
String s = driver.findElement(By.xpath(xpath)).getText().trim();
I added trim() to remove the BR spacing and other possible whitespace. You can remove it if it's not needed/wanted.
Based on OP's feedback, I would use the XPath above but I would change the assert to
By locator = By.xpath("//font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]");
List<WebElement> e = driver.findElements(locator);
Assert.assertTrue(e.size() > 0, "Verify text exists in email");
let me know did it help you or not,
If the current node is the font element, then something like this:
text()|span
otherwise you have to always combine with | the two complete XPath - the one for text and the one for span, e.g.:
font/text()|font/span
if the current node is just above font - or
//a[text()='View Larger Map']/../../../../div[contains(#class, 'paragraph')][3]/font/span|//a[text()='View Larger Map']/../../../../div[contains(#class, 'paragraph')][3]/font/text()
if starting from the root with some complex selection criteria.
If you have complex paths like the last one probably it is better to store a partial one in a variable - e.g. inside an XSLT:
<xsl:variable name="font" select="//a[text()='View Larger Map']/../../../../div[contains(#class, 'paragraph')][3]/font"/>
. . .
<xsl:for-each select="$font/span|$font/text()">
. . .
</xsl:for-each>
Another possibility is to do something like this:
//a[text()='View Larger Map']/../../../../div[contains(#class, 'paragraph')][3]/font/node()[name()='span' or name()='']
that works because name() returns an empty string for text() nodes - but I am not 100% sure that it works that way for all XPath processors, and it could match by mistake comment nodes.
below xpath should work
//font[contains(.,'Wij hebben uw bouwdepotdeclaratie verwerkt')]
or
//font[contains(text()[2],'Wij hebben uw bouwdepotdeclaratie verwerkt')]
As you were able to figure out the WebElement through the xpath //font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]/text() but through your script you are getting NoSuchElementException you need to induce WebDriverWait for the element to be visible as follows :
String myText = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("xpath_of_the_element"))).getText();
Update
As you are getting TimeoutException as an alternative you can induce WebDriverWait for the parent element to be visible and use Java Split method to extract the desired text as follows :
String myText = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//font[contains(text(),'Wij hebben uw bouwdepotdeclaratie verwerkt')]")));
String[] myTextParts = myText.split(Pattern.quote("<br>"));
String myPart = myTextParts[1];
System.out.println(myPart);
Related
<span id="UniversalRepositoryExplorer_treeNode7_name" style="white-space:nowrap;"> == $0
<img id="UniversalRepositoryExplorer_treeNodeIcon_7" src="../../images/server_running.gif"
style="width:16px;height:16px;" alt border="0"> == $0
" Running " == $0
tag span has inside tag img and below text Running doesn't have any tag name
I have tried the below x-path that didn't work:
//img[#id='UniversalRepositoryExplorer_treeNodeIcon_7']
Can someone suggest to me how to get Running through x-path?
Basically, you're trying to get the text node.
xpath: '//span/text()[last()]'
Example:
document.evaluate("//span/text()[last()]", window.document, null, XPathResult.ANY_TYPE, null).iterateNext()
// output: " Running "
Looking at the element you have noted above, if I was trying to evaluate for a cucumber step, I would write this for selenium-java:
#And("^I can view the \"([^\"]*)\" image$")
public void iCanViewTheImage(String text) throws Throwable {
String imgXpath = "//span[contains(text(),'" + text + "') and contains(#id, 'UniversalRepositoryExplorer_treeNode7_name')]//img[#id='UniversalRepositoryExplorer_treeNodeIcon_7']"
driver.findElement(By.xpath(imgXpath));
assertTrue(driver.findElement(By.xpath(imgXpath)).getText().contains(text));
}
where the regex "([^"]*)" would be "Running" in your cucumber step:
And I can view the "Running" image
Your xpath with the text based on the above will be:
//span[contains(text(),'Running') and contains(#id, 'UniversalRepositoryExplorer_treeNode7_name')]//img[#id='UniversalRepositoryExplorer_treeNodeIcon_7']
or simply
//span[contains(text(),'Running') and contains(#id, 'UniversalRepositoryExplorer_treeNode7_name')]
The problem with your locator is that an IMG tag is self-closing (there is no </img> tag) so it can't contain text. The parent SPAN is likely the element that contains the "Running" text.
You haven't posted valid HTML for the portion being discussed so the below HTML is what I'm guessing the general structure looks like.
<span id="UniversalRepositoryExplorer_treeNode7_name" style="white-space:nowrap;">
<img id="UniversalRepositoryExplorer_treeNodeIcon_7" src="../../images/server_running.gif" style="width:16px;height:16px;" alt border="0">
" Running "
</span>
Given that HTML, the code would look like
driver.findElement(By.id("UniversalRepositoryExplorer_treeNode7_name")).getText();
When you grab the SPAN and then use .getText(), it will get all the text contained within that SPAN. This is of course a guess since you haven't posted all the HTML under that span. This may get more than what you wanted but that's the best we can do with an incomplete question. If you add more details, we can adjust our answers.
The text Running is within a text node and it is the second child of it's parent <span> tag. So to retrieve the text you have to induce WebDriverWait for the visibilityOfElementLocated() and you can use either of the following Locator Strategies:
cssSelector:
System.out.println(((JavascriptExecutor)driver).executeScript("return arguments[0].childNodes[2].textContent;", new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("span#UniversalRepositoryExplorer_treeNode7_name")))).toString());
xpath:
System.out.println(((JavascriptExecutor)driver).executeScript("return arguments[0].childNodes[2].textContent;", new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//span[#id='UniversalRepositoryExplorer_treeNode7_name']")))).toString());
References
You can find a couple od relevant detailed discussions in:
How to extract just the number from html?
How do I use selenium to scrape text from a text node within a class through Python
How to retrieve partial text from a text node using Selenium and Python
I'm accessing a website with webdriver, and I want to change an element in it.
I want to know how to access an element and change it. In this case I want to add text to an element i.e. transform this:
<span data-id="tag-dist-Lisboa" title="Para eliminar uma das opções, faça duplo clique.">
</span>
Into this:
<span data-id="tag-dist-Lisboa" title="Para eliminar uma das opções, faça duplo clique.">
Some random text
</span>
My main problem has been finding the element.
I have added above some of the HTML, if you need more information please say so.
As I have already posted one answer on your previous question-
Use following code to set value for the span tag-
int textLength = driver.findElement(By.xpath("//span[#data-id='tag-dist-Lisboa']")).getText().length();
if(textLength<=0)
{
WebElement element = driver.findElement(By.xpath("//span[#data-id='tag-dist-Lisboa']"));
JavascriptExecutor js= (JavascriptExecutor)driver;
js.executeScript("arguments[0].innerText = 'Your Text Here'", element);
}
Explanation :-
Find your required span tag with data-id attribute and check if it contains text or not If yes then use that text value as per your choice.
If not then set your required text for that span tag
Let us know is it as per your question or some other you want to do ?
I am having a weird requirement. I am having a div class named "expandThisSection". And I have
<div id="requiredAccessoriesContentPlaceHolder" class="expandThisSection">No required accessories are available for this product.</div>
<div id="requiredAccessoriesContentPlaceHolderMeasurement" class="expandThisSection"> </div>
<div id="optionalAccessoriesContentPlaceHolder" class="expandThisSection">No optional accessories are available for this product.</div>
<div id="optionalAccessoriesContentPlaceHolderMeasurement" class="expandThisSection"> </div>
<div class="expandThisSection">
<div style="width:95%">mytext</div>
<ul class="movePos">…</ul>
<div><b>test</b></div>
<div><b>abc</b> Get this text</div>
<div id="vendLogo">…</div>
</div>
<div class="expandThisSection">
<table>...</table>
</div>
I want the content of the div that has style of 95% width.That is value I want is "mytext". But I am not able to find out xpath for the same.
Also I want xpath for finding the div content just above div with id="vendLogo". That is I want "Get this text".
NOTE: ITS ASSURED THAT THIS Bold tag WILL CONTAIN "abc"
How to do it? I am using selenium with Java
Got the first one. Not able to get second one.
Code:
List<WebElement> currentSkuDescription = driver.findElements(By.xpath("//div[#class='expandThisSection']/div"));
for(WebElement currentItem: currentSkuDescription) {
WebElement descriptionBlock = currentItem.findElement(By.xpath("//div[contains(#style, 'width:95%')]"));
description= descriptionBlock.getText();
}
Try dropping the #class='expandThisSection' because the div you want does not have that class attribute (it's parent does). Also, an exact match may be possible.
By.xpath("//div[#style='width:95%']
By.xpath("//div[contains(#style, 'width:95%')]
Either of those should work. If you want to make sure you are grabbing the right one, relative to the parent, use XPath axes...
//div[contains(#class, 'expandThisSection')]/child::div[contains(#style, 'width:95%')]
If you to search for the div by a specific text (in this case 'mytext') this you can use this xpath:
"//div[text()[contains(.,'mytext')]]/ancestor::div[#class='expandThisSection']"
Or if you want by the styling, the you can use this xpath:
"//div[#style='width:95%']/ancestor::div[#class='expandThisSection']"
Note that the second xpath will only work where the inline styling is done on the tag.
For the second query, try this xpath:
"//div[#id='vendLogo']/preceding-sibling::div[1]"
To get the specific text you require, you can do the following:
String text = driver.findElement(By.xpath("//div[#id='vendLogo']/preceding-sibling::div[1]")).getText();
text.replace(div.findElement(By.tagName("b")).getText(), "");
I want to find a p tag with class = "big-number". Here is the code I wrote:
WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.className("big-number")));
System.out.println(driver.getTitle());
System.out.println(myDynamicElement);
Here is my output:
[[FirefoxDriver: firefox on MAC (fed46ad4-9ca9-9344-a57a-1d336db3927c)] -> class name: big-number]
I cannot identify the error, it is giving me an output but its makes no sense to me.
Any tips on how I can at least identify my error?
I am certainly sure the element is present, here is the HTML code:
<div id="users-online-container" style="">
<img class="big-number-icon" src="images/usersOnline.png">
<p class="big-number">228</p>
<p class="caption">Users Online</p>
</div>
<div id="users-online-loading"></div>
TimeOutException occurs because driver cannot find element in specific time. Problem in selector i think. If you sure that element always visible, and exists on the page so try next code:
//Select first paragraph in div
driver.FindElement(By.CssSelector("#users-online-container .big-number"));
//if you have several p with same classes you could access any of them using index. e.g.
driver.findElements(By.CssSelector(".big-number"))[index];
Selectors can be #users-online-container .big-number or .big-number. Both will work.
Try below code..
WebElement myDynamicElement = (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(By.className("big-number")));
// It will print the text of the Element:
system.out.println(myDynamicElement.getText());
Also you try to locate the element with the help of XPATH and make sure your locator is uniquely identify the element. Also check that IsDisplayed() and IsEnabled() returns True.
In your code you are printing the WebElement that will print the Hashcode.
In order to get the text of the Element, you'll have to use getText() method.
Hope it will help!
Using Selenium WebDriver in a java class where I try to find that specific element and then automatically add a needed amount of that element in the input field.
I have an HTML table with each row specifying a type of element and an input field used to add X to the amount of element in the specific row.
<tr>
<td class="non-sortable-table">
<input class="required text" type="text" value="0" name="plate_order{pageFlow.plateorders[0].numberOfPlates}" tabindex="25">
</td>
<td class="non-sortable-table">
<span>20% - White plates</span>
</td>
...
</tr>
I have tried the following in my Java code in order to get that element, but with no luck:
WebElement element = (WebElement) js.executeScript("return ${\"document.getElementsByName('plate_order{pageFlow.plateorders[0].numberOfPlates}')\"");
WebElement element = driver.findElement(By.ByName('plate_order{pageFlow.plateorders[0].numberOfPlates}'))
how could i retreive that element in order to edit its input?
Is it possible when parts of the name of the element is a reference to a controller, i.e. pageFlow?
what if i wanted to retrieve the following element identified by 20% ....
I have tried to get that one using xpath and cssSelector with no luck.
Any suggestions?
To return an element from a JavaScript result, you can use the following syntax (i used jQuery as simplification):
RenderedWebElement webElement = (RenderedWebElement) ((JavascriptExecutor) webDriver).executeScript("return jQuery('input[name^=plate_order]').get(0);");
You can also pass an element which was previosly selected in Selenium:
((JavascriptExecutor) webDriver).executeScript("return doSomethingWithElement(arguments[0]);", webElement);
It looks to me like you might want to use a starts-with type operator in your XPath or CSS.
Something like:
XPath: //input[starts-with(#name, 'plate_order')]
CSS: input[name^='plate_order']
Similar things should work for the span, too (if you know the text):
XPath: //span[starts-with(., '20%')]
CSS/Sizzle*: span:contains('20%')
If you don't know the text, then something this xpath might work.
XPath: //input[starts-with(#name, 'plate_order]/../../td/span
* The contains function is not pure CSS. It's an addition provided by the Sizzle library. This may or may not work, depending on whether Selenium is using a built-in CSS library or injecting Sizzle.