I'm newbie with Test Automation. When I locating element through Firepath with target:
xpath=(//td[contains(#id, 'catProdTd_4723290')]/div/div[2]/h2)
Firefox founds that element and verify text.
But, when I trying to locate this element with Visual Studio 2012 and Selenium Web driver, I constantly have error: "Unable to locate element: {"method":"xpath","selector":"//td[contains(#id, 'catProdTd_4723290')]/div/div[2]/h2"}" .
I tried escaping:
//td[#id=\"catProdTd_4723290\"]/div/div[2]/h2
but nothing. When I use isElementPresent method, it founds elements.
Is there some special method or rule that should be use when writing Xpath for WebDriver ?
I defined ISelenium variable, WebDriver... Clicks works, WaitForPageToLoad works, but this can not locate element.
IWebElement we= driver.FindElement(By.XPath("//td[contains(#id, 'catProdTd_4723290')]/div/div[2]/h2"));
HTML from page:
<td class="productItem" id="catProdTd_4723290"><div class="product-details">
<div class="product-aside"> <img border="0" alt="Fork and Spoon Set" src="/_photos/store/glass-large.jpg" id="catlproduct_4723290">
</div>
<div class="product-main">
<h2 class="product-name">Fork and Spoon Set</h2>
<div class="price"><strong>$17.99</strong></div>
<hr>
<div class="attributes"></div>
<hr>
<div class="product-col-1">
<div class="qty"> Quantity: <strong><input type="text" value="1" name="AddToCart_Amount" class="productTextInput" id="Units_4723290"></strong></div>
<div class="stock">(N/A in-stock)</div>
</div>
<div class="product-col-2">
<input type="submit" onclick="AddToCart(192951,4723290,'',4,'','',true);return false;" value="Buy Now" name="AddToCart_Submit" class="productSubmitInput">
<div class="wish">Add to Wishlist</div>
</div>
<div class="product-description">
<h4>Product Information:</h4>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean
commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus
</div>
</div>
<!-- End Main -->
</div>
<!-- End Product Details -->
</td>
I must add that I try to wait during debug and with
Manage().Timeouts().ImplicitlyWait
but nothing. This happens on other places also. I using Firefox for tests
You are running into dynamic attributes.
My first recommendation to you. Switch to CSS.
My second recommendation, instead of boiling down into an entire parent-child hierarchy, why don't you just KISS!
So, lets look at your issue. You are trying to fetch the product name. Easy.. we can use classes here.
css=td.productItem h2.product-name
voila, it was that easy to fetch.. instead of having this huge ugly xpath selector, we've simplified it to a css selector.
So onto the next problem, if we have multiple of td.productItem's on the page, we can use a couple things.
Try,
css=td.productItem:nth-child(1) h2.productName
That will select the first td with class, productItem.
note: you may need to specify the td's parent.. e.g. css=div#container td.productItem:nth-child(1)
More specifics...
The reason your xpath is failing, is because of that catProdTd_4723290 id assigned to the <td> element being generated automatically, rendering that element unselectable. You can work around that, by doing starts with. for example, with css -
css=td[id^='catProdTd']
will select that <td> take note though, that there might be more than 1 element selected.
I suggest using such a method for waiting:
public bool boolWaitForElementIsDisplayed(By locator, int secondsToWait)
{
WebDriverWait Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(secondsToWait));
try
{
var FoundElement = Wait.Until<Boolean>(d =>
{
try
{
return (d.FindElement(locator).Displayed && d.FindElement(locator).Enabled);
}
catch
{
return false;
}
});
}
catch (WebDriverTimeoutException)
{
return false;
}
return true;
}
and then check as follows:
IWebElement h2Element = null;
string xpath = "//td[contains(#class,'productItem')]/div/div[contains(#class,'product-main')]/h2";
if (boolWaitForElementIsDisplayed(By.XPath(xpath), 30))
h2Element = Driver.FindElement(xpath);
So, the problem was that page isn't loaded. Why? Because WebElement.Click() not works. Why Click not working?! I don't know.
I resolved problem with clicks using JavascriptExecutor:
IJavaScriptExecutor executor = (IJavaScriptExecutor)chauffeur;
IWebElement webel1 = chauffeur.FindElement(By.CssSelector("#nav ul:nth-child(1) li:nth-child(2) a[href='/products']"));
Instead of using
webel1.Click();
which not works, I used:
executor.ExecuteScript("arguments[0].click();", webel1);
Related
I have two similar controller methods that I'm using to test the #PathVariable annotation with:
#RequestMapping(
value = "/1",
method = {RequestMethod.GET})
public String two(Model model)
{
model.addAttribute("category", "acategory");
model.addAttribute("subCategory", "placeholder");
return "homePage";
}
#RequestMapping(
path = "/{category}/{subcategory}",
method = {RequestMethod.GET})
public String three(
#PathVariable("category") String category,
#PathVariable("subcategory") String subcategory,
Model model)
{
model.addAttribute("category", "acategory");
model.addAttribute("subCategory", "placeholder");
return "homePage";
}
I would expect the exact same behavior from those two methods since I am not using the path variables passed in, and instead just hardcoding "acategory" and "placeholder". However when I navigate to localhost:8080/1 I see the content I expect but navigating to localhost:8080/asdf/asdf breaks my HTML.
Here is the HTML in question:
</head>
<body>
<div class="wrapper"> <!-- Entire page wrapper? -->
<!-- Thymeleaf fragment: commonHeader -->
<div th:replace="fragments/commonFragments :: commonHeader"></div>
<!-- Begin Page Content-->
<div th:insert="'fragments/' + ${category} :: ${subCategory}"></div>
<!-- End Page Content -->
</div> <!-- Entire page wrapper closing tag? -->
And the fragment:
<div th:fragment="placeholder">
<div class="container">
<div class="row tagline">
<div class="col-sm-12">
<p><strong>Please see page two for all related links. </strong>
<!--There's also a 3-column version of this page.--> Link to a
secondary page open accordion <a data-expand="#SecurityPanel" href="page2.html#collapse1">1</a>, <a
data-expand="#SecurityPanel" href="page2.html#collapse2">2</a>, or <a
data-expand="#SecurityPanel" href="page2.html#collapse3">3</a>.. Lorem ipsum dolor sit amet,
consectetur adipiscing elit. Vivamus hendrerit consectetur justo, vitae euismod nisl pulvinar id. In
hac habitasse platea dictumst. Nam quis ante at mi auctor vehicula. <a href="page2.html">Learn
more</a>. </p>
</div>
</div>
... more stuff cut for brevity
</div>
</div>
You probably have relative links to your CSS file, which break when you start using nested URLs. Change them to absolute links to fix it.
I have some trouble using TFHpple, so here it is :
I would like to parse the following lines :
<div class=\"head\" style=\"height: 69.89px; line-height: 69.89px;\">
<div class=\"cell editable\" style=\"width: 135px;\"contenteditable=\"true\">
<p> 1</p>
</div>
<div class=\"cell\" style=\"width: 135px;\" contenteditable=\"false\">
<p>2</p>
</div>
</div>
<div style=\"height: 69.89px; line-height: 69.89px;\" class=\"head\">
<div class=\"cell\" style=\"width: 135px; text-align: left;\"contenteditable=\"false\">
<p>3 </p>
</div>
<div class=\"cell\" style=\"width: 135px;\" contenteditable=\"false\">
<p>4</p>
</div>
</div>
<div style=\"height: 69.89px; line-height: 69.89px;\" class=\"\">
<div class=\"cell\" style=\"width: 135px;\" contenteditable=\"false\">
<p>5</p>
</div>
<div class=\"cell\" style=\"width: 135px;\" contenteditable=\"false\">
<p>6</p>
</div>
</div>
For now I would like to put the first level of div "element" (sorry I don't know the proper terminology) in an array.
So I have tried to do it by simply giving /div as the xPath to the searchWithXPathQuery methods but it simply doesn't find anything.
My second solution was to try using a path of this kind : //div[#class=\"head\"] but also allowing [#class=\"\"] but I don't even know if it is possible.
(I would like to do so because I need the elements to be in the same order in the array as they are in the data)
So here is my question, is there a particular reason why TFHpple wouldn't work with /div?
And if there is noway to just take the first level of div, then is it possible to make a predicate on the value of an attribute with xPath (here the attribute class) ? (And how ? I have looked quite a lot now and couldn't find anything)
Thanks for your help.
PS : If it helps, here is the code I use to try and parse the data, it is first contained in the string self.material.Text :
NSData * data = [self.material.Text dataUsingEncoding:NSUnicodeStringEncoding];
TFHpple * tableParser = [TFHpple hppleWithHTMLData:data];
NSString * firstXPath = #"/div";
NSArray<TFHppleElement *> * tableHeader = [tableParser searchWithXPathQuery:firstXPath];
NSLog(#"We found : %d", tableHeader.count);
You wrote:
Getting first level using TFHpple
I assume you mean: without also getting all descendants?
Taking your other requirements into account, you can do so as follows:
//div[not(ancestor::div)][#class='head' or #class='']
Dissecting this:
Select all div elements (yes, correct term ;) at any level in the whole document: //div
Filter with a predicate (the thing between brackets) for elements not containing a div themselves, by checking if there's some div ancestor (parent of a parent of a parent of a....) [not(ancestor::div)]
Filter by your other requirements: [#class='head' or #class='']
Note 1: your given XML is not valid, it contains multiple root elements. XML can have at most one root element.
Note 2: if your requirements are to first get all divs by #class or empty #class, and then only those that are "first level", reverse the predicates:
//div[#class='head' or #class=''][not(ancestor::div)]
You can use the following XPath expression to get div element -that's quite a correct term-, having class attribute value equals "head" or empty :
//div[#ciass='head' or #class='']
I'm trying to verify the text in the span by using WebDriver. There is the span tag:
<span class="value">
/Company Home/IRP/tranzycja
</span>
I tried something like this:
driver.findElement(By.xpath("//span[#id='/Company Home/IRP/tranzycja']'"));
driver.findElement(By.cssSelector("span./Company Home/IRP/tranzycja"));
but none of this work.
Any help would be really appreciated. Thanks
More code:
<span id="uniqName_64_0" class="alfresco-renderers-PropertyLink alfresco-renderers-Property pointer small" data-dojo-attach-point="renderedValueNode" widgetid="uniqName_64_0">
<span class="inner" tabindex="0" data-dojo-attach-event="ondijitclick:onLinkClick">
<span class="label">
In folder:
</span>
<span class="value">
/Company Home/IRP/tranzycja
</span>
</span>
uniqName shouldn't be a target because are a lot of them and they are change.
There is a full html code:
http://www.filedropper.com/spantag
Here I am assuming you are trying to verify the text in the span tag.
i.e '/Company Home/IRP/tranzycja'
Try Below code
String expected String = "/Company Home/IRP/tranzycja";
String actual_String = driver.findElement(By.xpath("//span[#class='alfresco-renderers-PropertyLink alfresco-renderers-Property pointer small']//span[#class='value']")).getText();
if(expected String.equals(actual_String))
{
System.out.println("Text is Matched");
}
else
{
System.out.println("Text is not Matched");
}
You can try using xpath ('some text' can be replaced by variable like #Rupesh suggested):
driver.findElement(By.xpath("//span/span[#class='value'][normalize-space(.) = 'some text']"))
or
driver.findElement(By.xpath("//span/span[#class='value'][contains(text(),'some text')]"))
(Be aware that this xpath will find first matching element, so if there are span elements with text 'some text 1' and 'some text 2', only first occurrence will be found.)
Of course, those two methods will throw NoSuchElementException if element (with defined text) is not found on page. If you're using Java and if needed, you can easy catch that error and print proper message.
One possible xpath to find that <span> element :
//span[normalize-space(.) = '/Company Home/IRP/tranzycja']
I think your going to want to use something like
driver.findElement(By.xpath("//span[#id='/Company Home/IRP/tranzycja'])).getText();
the getText(); will get the text within that span
You can use text() method inside Xpath. I hope this will resolve your problem
String str1 = driver.findElement(By.xpath("//span[text()='/Company Home/IRP/tranzycja']")).getText();
System.out.println("str1");
Output = /Company Home/IRP/tranzycja
(using dojo 1.10.1)
I am working with dojo's dijit/layout/StackContainer and dijit/layout/StackController which are working fine, here is a simplified example. My problem is that I cant find a "clean" way to add mouseover titles to each controller button that the StackController creates?
html
<div>
<div data-dojo-type="dijit/layout/StackContainer"
data-dojo-props="id: 'contentStack'">
<div data-dojo-type="dijit/layout/ContentPane" title="one">
<h4>Group 1 Content</h4>
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="two">
<h4>Group 2 Content</h4>
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="three">
<h4>Group 3 Content</h4>
</div>
</div>
<div data-dojo-type="dijit/layout/StackController" data-dojo-props="containerId:'contentStack'"></div>
</div>
So for each title in each child contained within the StackContainer, a button is cerated by the StackController with the same label, but the button has no mouseover text, I need to add that as well.
I am not interested in any solution that involves me looping over the nodes and finding each button, its just not nice.
One of the best solutions would be to send properties, methods and events of buttons via corresponding ContentPanes. For example:
<div data-dojo-type="dijit/layout/ContentPane" title="one" data-dojo-props=
"controllerProps: {onMouseOver: function(){"doSomething"}}">
<h4>Group 1 Content</h4>
</div>
But as far as I understood this is not possible, because StackController passes to its buttons "title" and some other unimportant properties of ContentPane. So if you are really interested in above solutions you have to override the default behavior of StackController. Which is possible, but needs more time! :)
So I suggest you other solution which works and faster. You give to StackController-div an id:
<div id="myController" data-dojo-type="dijit/layout/StackController" data-dojo-
props="containerId:'contentStack'"></div>
You use "dijit/registry" to call that id:
var controllerWidget = registry.byId("myController");
You have now StackController widget. Call getChildren() method of it and you have an array of Button widgets. The rest I guess straightforward.
Here is the JSFiddle example.
Cheers!
Update:
Hey I have found another solution, which satisfies your requirements: "No button search"
These are the properties which StackController passes to buttonWidget:
var Cls = lang.isString(this.buttonWidget) ? lang.getObject(this.buttonWidget) : this.buttonWidget;
var button = new Cls({
id: this.id + "_" + page.id,
name: this.id + "_" + page.id, // note: must match id used in pane2button()
label: page.title,
disabled: page.disabled,
ownerDocument: this.ownerDocument,
dir: page.dir,
lang: page.lang,
textDir: page.textDir || this.textDir,
showLabel: page.showTitle,
iconClass: page.iconClass,
closeButton: page.closable,
title: page.tooltip,
page: page
});
So if you give a tag "tooltip" for your ContentPane, it will appear in buttonWidget as "title".
<div data-dojo-type="dijit/layout/ContentPane" title="one" tooltip="First Page">
Here is another JSFiddle example.
This question already has answers here:
Getting text from a node
(5 answers)
Closed 5 years ago.
I want to get the text from a tag but without the text from nested tags. I.e. in the example below, I only want to get the string 183591 from inside the <small> tag and exclude the text Service Request ID: from the <span> tag. This is not trivial because the <span> tag is nested in the <small> tag. Is this possible with WebDriver and XPath?
The text in the tag is going to change every time.
<div id="claimInfoBox" style="background-color: transparent;">
<div class="col-md-3 rhtCol">
<div class="cib h530 cntborder">
<h4 class="no-margin-bottom">
<p>
<small style="background-color: transparent;">
<span class="text-primary" style="background-color: transparent;">Service Request ID:</span>
183591
</small>
</p>
<div class="border-bottom" style="background-color: transparent;"></div>
<div id="CIB_PersonalInfo_DisplayMode" class="cib_block">
<div id="CIB_PersonalInfo_EditMode" class="cib_block" style="display: none">
</div>
</div>
<script type="text/javascript">
</div>
</div>
You are going to have to use String manipulation. Something like:
// you will need to adjust these XPaths to suit your needs
String outside = driver.findElement(By.xpath("//small")).getText();
String inside = driver.findElement(By.xpath("//span")).getText();
String edge = outside.replace(inside, "");
The simplest way I've found is by getting the parent small node and the child span node and removing the number of characters in the child from the text of the parent:
public String getTextNode() {
WebElement parent = driver.findElement(By.xpath("//small")); //or By.tagName("small")
WebElement child = parent.findElement(By.xpath(".//span")); //or By.tagName("span")
return parent.getText().substring(child.getText().length()).trim();
}
The actual simplest way is using javascript executor as below:
JavascriptExecutor js = ((JavascriptExecutor)driver);
js.executeScript("return $(\"small\").clone().children().remove().end().text();");
This will return the text associated with the parent element 'small' only. Use trim() to omit leading and trailing whitespace. For the full explanation of what is happening here, please refer the link below.
Reference:
http://exploreselenium.com/selenium/exclude-text-content-of-child-elements-of-the-parent-element-in-selenium-webdriver/