Selenium XPath not recognizing text in table cell - c#

I am trying to do some unit testing with selenium2 using the following code:
private const string TicketName = "Automated Test Ticket";
[Test]
public void EditTicketTest() {
var tableData = driver.FindElement(By.XPath("//td[contains(text(), '" + TicketName + "')]"));
}
The test fails with the following reason:
OpenQA.Selenium.NoSuchElementException : Unable to locate element: {"method":"xpath","selector":"//td[contains(text(), 'Automated Test Ticket')]"}
But when I look at the page and inspect the element, the text is definitely inside the tag. Is it possible that there is some excess spacing or something else that could be causing it to not recognize the text?
Here is the HTML:
<tr data-id="55">
<td>55</td>
<td class="ticket-title">
<span data-original-title="Automated Test Ticket" class="work-on-ticket-note-icon-tickets" data-toggle="tooltip" data-placement="right" data-trigger="hover" title=""></span> <span data-original-title="This is a work on ticket note for a company!" class="work-on-ticket-note-icon-companies" data-toggle="tooltip" data-placement="right" data-trigger="hover" title=""></span> Automated Test Ticket
</td>
<td>Medium</td>
<td>Active</td>
<td>8/25/2014<br> <small>(0 changes)</small></td>
<td></td>
<td>
<strong class="text-danger">None Assigned</strong>
</td>
<td>
<span class="glyphicon glyphicon-edit"></span>
<span class="glyphicon glyphicon-list-alt"></span>
<span class="glyphicon glyphicon-time"></span>
</td>
</tr>

The td in question contains multiple empty text nodes as children, and when text() is used in a function that takes a string, it will evaluate to the string value of the first matching node in document order, so this:
//td[contains(text(), 'Automated Test Ticket')]
Is evaluating to something like this:
//td[contains(" ", 'Automated Test Ticket')]
Which will always produce an empty nodeset.
Two options here are this:
//td[contains(., 'Automated Test Ticket')]
which will match any td that has a contiguous "Automated Test Ticket" anywhere within it, or this:
//td[text()[contains(., 'Automated Test Ticket')]]
which will match any td that has an immediate child text node containing the text "Automated Test Ticket".
I prefer the first option because it's cleaner and has a better chance of turning up a match if you're not completely sure what the td is going to contain.

Related

How do I get my XPath to search only within each table?

I have a bit of HTML that looks like this:
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ACME ANVILS, INC</td>
</tr>
</tbody>
</table>
and some C# code that looks like this:
var name = document.DocumentNode
.SelectSingleNode("//*[text()='Name']/following::td").InnerText
which happily returns
ACME ANVILS, INC.
However, there's a new wrinkle. The page in question now returns multiple results:
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ACME ANVILS, INC.</td>
</tr>
</tbody>
</table>
<table class="resultsTable">
<tbody>
<tr class="even">
<td width="35%"><strong>Name</strong></td>
<td>ROAD RUNNER RACES, LLC</td>
</tr>
</tbody>
</table>
So now I'm working with
var tables = document.DocumentNode.SelectNodes("//table/tbody");
foreach (var table in tables)
{
var name = table.SelectSingleNode("//*[text()='Name']/following::td").InnerText;
...
}
Which falls over, because SelectSingleNode returns null.
How do I get my XPath to actually return a result, searching only within the specific table I have selected?
With the addition of a second table, two adjustments are required:
Change your absolute XPath,
//*[text()='Name']/following::td
to one relative to the current table or tbody element:
.//*[text()='Name']/following::td
Account for there now being more than one td element on the
following:: axis.
Either just grab the first,
(.//*[text()='Name']/following::td)[1]
or, better, use the following-sibling:: axis instead in combination
with a test on the string value of td rather than a test on a text node, which might be buried beneath intervening formatting elements:
.//td[.='Name']/following-sibling::td
See also Difference between Testing text() nodes vs string values in XPath.

HtmlAgilityPack adding div elements to existing html file

This is my original html:
<tr>
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">Tove</font></td>
<td style="padding-left: 40pt;"><font style="background-color: lightgreen" color="black">To</font></td>
</tr>
And my goal is to have this:
<div class="select-me" /> <tr>...<tr/>
I am using HtmlAgilityPack and essentially going through each font tag and checking to see if it's style is light-green. But I'm not sure how to jump to back the table row tags and put a div tag around the table row tags.
You can use the following code to wrap them with div:
foreach(var node in selectMe)
node.ParentNode.OuterHtml = "<div class=\"select-me\">" + node.ParentNode.InnerHtml + "</div>";
Also you can select selectMe with this instead of checking one by one:
var selectMe = doc.DocumentNode.SelectNodes("//td[contains(#style,'background-color: lightgreen')]");

Multiplying a textbox with a cell in a dynamically created table with JQuery

I have a dynamically created table with id called "editTable" that looks as follows:
<tbody>
#{var i = 0;}
#foreach (var item in Model)
{
<tr>
<td width="25%">
#Html.DisplayFor(modelItem => item.Product.Name)
</td>
<td width="25%">
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td width="25%">
<div class="editor-field">
#Html.EditorFor(modelItem => item.UnitPrice)
#Html.ValidationMessageFor(model => item.UnitPrice)
</div>
</td>
<td width="25%" id="total"></td>
</td>
</tr>
}
</tbody>
The 3th td-element consists of a C# textbox that is turned into a element in html.
Now I want to multiply the quantity by the unit price to display this value in the 4th td element next to it. This value should update every time the value in the textbox is adjusted. I am a newbie at JQuery / JavaScript and came up with the following code:
// Calculating quantity*unitprice
$('#editTable tr td:nth-child(3) input').each( function (event) {
var $quant = $('#editTable tr td:nth-child(2)', this).val();
var $unitPrice = $('#editTable tr td:nth-child(3) input', this).val();
$('#editTable tr td:nth-child(4)').text($quant * $unitPrice);
});
This doesn't work and only displays NaN in the 4th element. Can anyone help me updating this code to a working version? Any help would be very much appreciated.
I geussed you accidentally switched units and price because it has more logic to change the number of units then the price. I took your html and javascript and tried to change as little as possible to make it work (I'm not saying the solution is perfect, I just don't want to give you a totaly different example of how to do it).
The html (The C# is irrelevant for this problem):
<table id="editTable">
<tbody>
<tr>
<td width="25%">
Product name
</td>
<td width="25%">
5
</td>
<td width="25%">
<div class="editor-field">
<input id="UnitPrice" name="UnitPrice" type="number" value="2" style="width:40px" />
</div>
</td>
<td width="25%" id="total"></td>
</tr>
</tbody>
</table>
The javascript/jquery (which should run on load):
$('#editTable tr td:nth-child(3) input').each(updateTotal);
$('#editTable tr td:nth-child(3) input').change(updateTotal);
var element;
function updateTotal(element)
{
var quantity = $(this).closest('tr').find('td:nth-child(2)').text();
var price = $(this).closest('tr').find('td:nth-child(3) input').val();
$(this).closest('tr').find('td:nth-child(4)').text(quantity * price);
}
The problem you had were with jquery. I've created a function that recieves an element (in our case it's your UnitPrice input), then it grabs the closest ancestor of type tr (the row it's in) and from there it does what you've tried to do.
You've used jquery selector to get all 2nd cells in all table rows, the closest('tr').find limits it to the current row.
You've tried to use .val() on a td element, you should use either .text() or .html(). Instead, You can also add a data-val="<%=value%>" on the td and then use .data('val').
It will be better to take the units directly from $(element).val() and no going to the tr and then back into the td and the input.
To see it working: http://jsfiddle.net/Ynsgf/1/
I hope I didn't caused you any confusion with my explanation and the options I gave you.
Here is another way to write the jquery part.
$('#editTable tr').each(function (i, row) {
var $quant = $(row).find('.editor-field input').val();
var $unitPrice = $(row).find('.editor-field input').val();
$(row).find('td:nth-child(4)').text($quant * $unitPrice);
});

WebMatrix filling attribute and JavaScript Reading Attribute not producing expected results

I am having an issue with the following code:
SECTION FROM CSHTML FILE:
#if(errorMessage != "")
{
err="err";
}
else
{
err="";
}
#if(errorMessage == "")
{
foreach(var row in db.Query(stringCompiler, EntryID, POIName, DateLastModified, Gender, Race, Height, Weight, HairColor, EyeColor, DOB, Age, SS, DL, DOC, VehicleTag, FBI, Officer, HomePhone, CellPhone, CellPhone2, CellPhone3, POICautions, WorkPhone, WeightedAggregate, Address, AdditionalDescriptors, Aliases, SourceOfInformation, AddressInformation, KnownAssociates, VehicleDescription, Comments, SummarizedIncidents, AllCellPhones, AllPhones, betDOB1, betDOB2, betDLM1, betDLM2, betAge1, betAge2, POILastName, SearchAll))
{
<div class="searchResult">
<table style="background-color: #beebeb;">
<tr>
<td class="entryLabel">ENTRY ID</td>
<td class="entryLabel">FIRST NAME</td>
<td class="entryLabel">LAST NAME</td>
<td class="entryLabel">DATE LAST MODIFIED</td>
<td class="entryLabel">DOB</td>
<td class="entryLabel">AGE</td>
<td class="entryLabel">ADDRESS</td>
<td class="entryLabel">VEHICLE TAG#</td>
<td class="entryLabel">OFFICER</td>
<td class="entryLabel">HOME PHONE</td>
<td class="entryLabel">CELL PHONE</td>
<td class="entryLabel">WEIGHTED AGGREGATE</td>
</tr>
<tr>
<td class="entry">#row.EntryID</td>
<td class="entry">#row.POIName</td>
<td class="entry">#row.POILastName</td>
<td class="entry">#row.DateLastModified</td>
<td class="entry">#row.DOB</td>
<td class="entry">#row.Age</td>
<td class="entry">#row.Address</td>
<td class="entry">#row.VehicleTag</td>
<td class="entry">#row.Officer</td>
<td class="entry">#row.HomePhone</td>
<td class="entry">#row.CellPhone</td>
<td class="entry">#row.WeightedAggregate</td>
</tr>
<tr>
<td colspan="13" style="text-align: center;"><form method="post" action="/ComputeLookupToVAndE.cshtml"><input type="hidden" name="veEntryID" hidden="hidden" readonly="true" value="#row.EntryID" /><br/><input type="submit" value="View & Edit" class="btn3" style="height: 40px; width: 100px;" /><br/><br/></form></td>
</tr>
</table>
</div><br/>
ResultCount += 1;
}
<input type="hidden" id="ResultCount" value="#ResultCount" />
<input id="err" type="hidden" value='#err' />
}
SECTION FROM JAVASCRIPT FILE:
$(document).ready(function () {
if ($("#err").val() == "err")
{
$("#searchForm").attr('action', "/LookUpEntry.cshtml#top");
}
else
{
$("#searchForm").attr('action', "/LookUpEntry.cshtml#searchList");
}
});
Obviously I am trying to change the value of the hidden input element to "err" before the page is rendered by C# if any error messages have been stored in the variable errorMessage.
Once done JavaScript is supposed to read this value and then if it is "err" change the action attribute of the form to append "#top" (for named anchor, so the loaded position on the page changes based off of whether there is an error message or results to view), otherwise the form's action attribute should be changed (still by JavaScript) to append #searchList).
Any idea why JavaScript and C# won't play well together? The errors I am getting are haphazard (like it won't work the first time, then doesn't work at all), anyway based on the code below, it still never goes to (#top), although when trying a few things before this exact coding (I don't remember exactly what they were) it would sometimes (although never the first time) go to the top if it had errored.
Why is jQuery not doing its job? It seems like this should just work to me...
Any ideas?
Thanks for any help
Well, I guess I have it figured out and I suppose it does make sense:
It does change the value as it should, but the action (how the form [or rather where, the way I look at it] handles the data posted) is already set to what it where it will go regardless of the results of the current search. In short: It is a step behind. When I click to search and an error Message is produced, it will rewrite the action as intended, but it will, of course, only come into effect on the next search not the current one as that was already determined on the previous submit.
What's wrong with my code? Nothing syntactically, the methodology (logic) is in err.

Finding the child of a parent's sibling element with WatiN

The scenario that I am looking at is that we have a table with multiple columns. One of those columns has a name, another has a dropdown list. I need to manipulate the dropdown for a row that contains a particular name. I looked at the source output, and tried getting the element's grandparent (the table row) so that I could search for the list. However, there was no such search functionality when I used the parent object.
It seems like there would be a lot of this kind of scenario in automating/testing a site, but I have not found anything after searching for a couple of hours. Any help would be appreciated.
EDIT: The application in question is an ASP.NET, and the output HTML is gnarly at best. However, here is a cleaned up example of what the HTML being searched looks like:
<table class="myGrid" cellspacing="0" cellpadding="3" rules="all" border="1" id="ctl00_content_MyRpt_ctl01_MyGrid" style="border-collapse:collapse;">
<tr align="left" style="color:Black;background-color:#DFDBDB;">
<th scope="col">Name</th><th scope="col">Unit</th><th scope="col">Status</th><th scope="col">Action</th>
</tr>
<tr>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_Name">JOHN DOE</span>
</td>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_UnitType">Region</span>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_UnitNum">1</span>
</td>
<td>
<span id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_Status">Complete</span>
</td>
<td class="dropdown">
<select name="ctl00$content$MyRpt$ctl01$MyGrid$ctl02$ActionDropDown" onchange="javascript:setTimeout('__doPostBack(\'ctl00$content$MyRpt$ctl01$MyGrid$ctl02$ActionDropDown\',\'\')', 0)" id="ctl00_content_MyRpt_ctl01_MyGrid_ctl02_ActionDropDown" class="dropdown">
<option value="123456">I want to...</option>
<option value="Details.aspx">View Details</option>
<option value="Summary.aspx">View Summary</option>
<option value="DirectReports.aspx">View Direct Reports</option>
</select>
</td>
</tr>
<tr>
...
</tr>
</table>
I found a way to do what I wanted. It is probably not the best or most elegant solution, but it works (it is not production code).
private void btnStart_Click(object sender, EventArgs e)
{
using (var browser = new IE("http://godev/review"))
{
browser.Link(Find.ByText("My Direct Reports")).Click();
TableRow tr = browser.Span(Find.ByText("JOHN DOE")).Parent.Parent as TableRow;
SelectList objSL = null;
if (tr.Exists)
{
foreach (var td in tr.TableCells)
{
objSL = td.ChildOfType<SelectList>(Find.Any) as SelectList;
if (objSL.Exists) break;
}
if (objSL != null && objSL.Exists)
{
Option o = objSL.Option(Find.ByText("View Direct Reports"));
if (o.Exists) o.Select();
}
}
}
}
Hopefully this saves someone a little time and effort. Also, I would love to see if someone has a better solution.

Categories

Resources