Assert all the li in the div in coded UI test - c#

<div class="validation-summary-errors">
<span>Please check the following entries:</span>
<ul>
<li>Please select a client account</li>
<li>Please select a beneficiary account</li>
</ul>
</div>
public virtual T VerifyAmountValidationMessages()
{
HtmlDiv error = new HtmlDiv(_browserWindow);
error.SearchProperties[HtmlDiv.PropertyNames.Class] = "validation-summary-errors";
var errors = error.FindMatchingControls();
var errorLi = error.GetChildren()[0];
foreach (var item in errors)
{
Assert.IsTrue(item.GetProperty("InnerText").ToString().Contains("Please check the following entries:\r\nPlease select a client account\r\nPlease select a beneficiary account"));
}
return (T)this;
}
How can I iterate all the lis and assert the inner text of each Li, with the getChildren I can access the span element individually but I want to access the Li individually? Right Now I am asserting the whole text which is not the correct approach at all.

The ul element would be errors.GetChildren()[0]; you would them loop over its children.
<div class="validation-summary-errors">
<span>Please check the following entries:</span>
<ul>
<li>Please select a client account</li>
<li>Please select a beneficiary account</li>
</ul>
</div>
public virtual T VerifyAmountValidationMessages()
{
HtmlDiv error = new HtmlDiv(_browserWindow);
error.SearchProperties[HtmlDiv.PropertyNames.Class] = "validation-summary-errors";
var errors = error.FindMatchingControls();
var errorul = error.GetChildren()[1];
foreach (var item in errors
{
// check individual li items
}
return (T)this;
}
This would seem to be a brittle test though, consider if any changes are made to how errors are displayed, you'll have to rewrite the test.

Related

XPath, select multiple elements from multiple nodes in HTML

I just can't figure this one.
I have to search through all nodes that have classes with "item extend featured" values in it (code below). In those classes I need to select every InnerText of <h2 class="itemtitle"> and href value in it, plus all InnerTexts from <div class="title-additional">.
<li class="item extend featured">
<div class="title-box">
<h2 class="itemtitle">
<a target="_top" href="www.example.com/example1/example2/exammple4/example4" title="PC Number 1">PC Number 1</a>
</h2>
<div class="title-additional">
<div class="title-km">150 km</div>
<div class="title-year">2009</div>
<div class="title-price">250 €</div>
</div>
The output should be something like this:
Title:
href:
Title-km:
Title-year:
Title-Price:
--------------
Title:
href:
Title-km:
Title-year:
Title-Price:
--------------
So, the question is, how to traverse through all "item extend featured" nodes in html and select items I need above from each node?
As I understand, something like this should work but it breaks halfway
EDIT: I just noticed, there are ads on the site that share the exact same class and they obviously don't have the elements I need. More problems to think about.
var items1 = htmlDoc.DocumentNode.SelectNodes("//*[#class='item extend featured']");
foreach (var e in items1)
{
var test = e.SelectSingleNode(".//a[#target='_top']").InnerText;
Console.WriteLine(test);
}
var page = new HtmlDocument();
page.Load(path);
var lists = page.DocumentNode.SelectNodes("//li[#class='item extend featured']");
foreach(var list in lists)
{
var link = list.SelectSingleNode(".//*[#class='itemtitle']/a");
string title = link.GetAttributeValue("title", string.Empty);
string href = link.GetAttributeValue("href", string.Empty);
string km = list.SelectSingleNode(".//*[#class='title-km']").InnerText;
string year = list.SelectSingleNode(".//*[#class='title-year']").InnerText;
string price = list.SelectSingleNode(".//*[#class='title-price']").InnerText;
Console.WriteLine("Title: %s\r\n href: %s\r\n Title-km: %s\r\n Title-year: %s\r\n Title-Price: %s\r\n\r\n", title, href, km, year, price);
}
What you are trying to achieve requires multiple XPath expressions as you can't return multiple results at different levels using one query (unless you use Union perhaps).
What you might be looking for is something similar to this:
var listItems = htmlDoc.DocumentNode.SelectNodes("//li[#class='item extend featured']");
foreach(var li in listItems) {
var title = li.SelectNodes("//h2/a/text()");
var href = li.SelectNodes("//h2/a/#href");
var title_km = li.SelectNodes("//div[#class='title-additional']/div[#class='title-km']/text()");
var title_... // other divs
}
Note: code not tested

how to "Paginate" results into rows not pages

This one is very difficult for me to word, which is what is failing me in my google searching, i brand new to asp.net and it's giving me some difficulties with the logic of this requirement
I have a bunch of results which are displayed primarily as images with some text overlayed.
I have some HTML that is required to show these images, but it uses custom styling to show each "row" of images, it uses div's for a custom look.
What i'm needing to do, is work out a way in the cshtml file display a html block to start a row, and then output the html for 6 of the items, then close off that row and begin another one and rinse repeat until completed, but i cannot for the life of me work out how i would go about that in asp.net.
This might be a very very simple issue, but due to my inability to word this correctly for google, I'm really struggling to find anything online.
The closest visual example i can think of is something like Netflix, but without the ability to scroll the movies, so all the movies are listed in those rows.
i'm currently using the following method,
#foreach (var item in Model)
{
html...
}
My original thought was to have a counter and do a conditional statement when the count hit's six, closing the row and starting a new one, but i cannot work out how to mix that much html into code blocks.
#{
int count = 0;
foreach(var item in model)
{
count++;
//Output current item's html
if(count == 6)
{
//End current row, start new row
count = 0;
}
}
but as i mentioned, i can only find how to mix single html elements in with code blocks using the #: method, and i need a block of html.
Adding my controller code as requested, I have it kinda working using viewbag, but the groupedModel seems to split each movie into a separate row.
// GET: Movies
public ActionResult Index(string movieGenre, string searchString)
{
var GenreList = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreList.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreList);
var movies = from m in db.Movies
select m;
if(!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if(!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
var groupedModel = movies.AsEnumerable().Select((e, i) => new { Element = e, Index = i }).GroupBy(e => e.Index % 6).Select(g => g.Select(e => e.Element));
ViewBag.grouped = groupedModel;
return View(movies);
}
and my view (With most of the HTML removed for ease of reading):
#model IEnumerable<MvcMovie.Models.Movie>
#{
ViewBag.Title = "Index";
}
<p>
#Html.ActionLink("Create New", "Create")
#using (Html.BeginForm("Index", "Movies", FormMethod.Get))
{
<p>
Genre: #Html.DropDownList("movieGenre", "All")
Title: #Html.TextBox("SearchString")
<input type="submit" value="Filter" />
</p>
}
</p>
#foreach(var group in ViewBag.grouped)
{
<div class="MovieRow">
#foreach (var item in group)
{
<div class="bob-title">#Html.Display((item as MvcMovie.Models.Movie).Title)</div>
}
</div>
}
EDIT:
The only problem i have left now, is that i can't seem to get the item variables to output, none of the #Html.Display((item as MvcMovie.Models.Movie) sections output anything.
First, let's group your model to get groups with 6 elements (better to do it in the controller, not in the view):
var groupedModel = Model.Select((e, i) => new { Element = e, Index = i })
.GroupBy(e => (e.Index - 1) / 6)
.Select(g => g.Select(e => e.Element));
than you will iterate these group and display them:
#foreach(var group in groupedModel)
{
<div id="rowDiv">
#foreach(var element in group)
{
<div id="elementDiv">// element div here
// display element info here
</div>// element div end
}
</div> // row div end
}

razor html output result

I am trying to output the results in my #helpers code and the code looks like this
#helpers listfiles(String ID, String CNumber,){
foreach(Loopitem I in GetLoop("items")){
if(I.GetValue("userId") == ID){
<li>#I.GetValue("name")</li>
}else{
If(I.GetValue("userId") != ID){
<li>#I.GetValue("name")</li>
}
}
}
}
As a result I get all li elements but what I want is that if the statement is true it should wrap all the li elements in ul element and for the else statement it should wrap all the li in new UL element. Please help
One possible way by using two foreach, one for each user ID group :
#helpers listfiles(String ID, String CNumber,){
<ul>
foreach(Loopitem I in GetLoop("items").Where(o => o.GetValue("userId") == ID)){
<li>#I.GetValue("name")</li>
}
</ul>
<ul>
foreach(Loopitem I in GetLoop("items").Where(o => o.GetValue("userId") != ID)){
<li>#I.GetValue("name")</li>
}
</ul>
}
You mean something like this:
#helpers listfiles(String ID, String CNumber,){
var lstTrue = new List<>();
var lstFalse = new List<>();
foreach(Loopitem I in GetLoop("items")){
if(I.GetValue("userId") == ID)
lstTrue.Add(I);
else
lstFalse.Add(I);
}
if(lstTrue.Count()>0)
{
<ul> foreach(var I in lstTrue){<li>#I.GetValue("name")</li>}</ul>
}
if(lstFalse.Count()>0)
{
<ul> foreach(var I in lstTrue){<li>#I.GetValue("name")</li>}</ul>
}
}
Or you can make use of Lambda expression to reduce lines of code.

Checking Umbraco node length

I have a panel that is created and filled via a vacancy page I have created. Im doing it as follows:
#{
var root = CurrentPage.AncestorOrSelf(1);
var newsNode = root.Descendants("News").First();
var vacanciesNode = root.Descendants("Vacancies").First();
string shortenedSummary = string.Empty;
}
<ul>
#foreach (var vacancyItem in vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc"))
{
<p>here we are 2</p>
#vacanciesNode.Count().ToString()
<li>
<h4>#vacancyItem.jobTitle</h4> <span>Posted on #vacancyItem.postDate.ToString("dd/MM/yyyy")</span>
<p>
#if (vacancyItem.jobSummary.Length <= 182)
{
#vacancyItem.jobSummary
}
else
{
shortenedSummary = vacancyItem.jobSummary.Substring(0, 182) + "...";
#shortenedSummary
}
</p>
Read More..
</li>
}
</ul>
However, when there are no vacancy items, my list is empty. Should this be the case, I'm wanting it to read "sorry no vacancies just now" but I don't know how to check if my vacanciesNode has any items in it.
Could someone show me how I could achieve this?
Since the .Descendants() method returns a DynamicContentList (a collection) you can simply do a .Count() on the collection and check whether it's more than or equal to 1.
If there's more than 0 items in the collection, it's not empty.
So, what you need to do is surround your #foreach with an #if statement which checks on this, and an else statement after that prints whatever html you want to show if there's no vacancies
#if( vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc").Count() > 0) {
//Do foreach
}
else
{
//Write message about missing vacancies
}

Nested list of SQL query result

After I run my query I have got the result into a dataTable as the following (this is only a simplified resultset):
food_cat food
-----------------------
vegit carrot
vegit onion
vegit tomato
fruit cherry
fruit banana
fruit orange
I want to list that result grouped by food_cat in an unordered list.
<h3> Vegit </h3>
<ul>
<li>carrot</li>
<li>onion</li>
<li>tomato</ti>
</ul>
<h3>fruit</h3>
<ul>
<li>cherry</li>
<li>banana</li>
<li>orange</li>
</ul>
I have tried some for, if, while controls but could not find a good solution.
since you don't provide table names etc. i will try to give the answer in general way.
string previous_food_cat = '';
bool firstEntrance = true
while(trace resultSet until no elements left)
{
if resultSet.food_cat != previous_food_cat //check if food_cat value changed
{
if (!firstEntrance) //if not first entrance close the <ul> tag before opening new one
{
print </ul>
}
print <h3> resultSet.food_cat </h3> //open new <h3> tag
print <ul> //open new <ul> tag
previous_food_cat = resultSet.food_cat //update previous_food_cat for new food_cat value
firstEntrance = false //set firstEntrance false so that ul tqags should be closed
}
print <li> resultSet.food </li>
}
Thank you #zibidyum, your technic obtained me to reach a solution. But final solution is here:
public bool firstcat; // defined at before Page_Load method
public int temp_cat; // defined at before Page_Load method
for (int i = 0; i < dt.Rows.Count; i++)
{
if (temp_cat != Convert.ToInt32(dt.Rows[i]["food_cat"]))
{
if (i > 0 && !firstcat)
content.InnerHtml += "</ul>"; //solution's most critic point is here
content.InnerHtml += "<ul>"
}
content.InnerHtml += String.Format("<li>{0}</li>", dt.Rows[i]["food"].ToString());
temp_cat = Convert.ToInt32(dt.Rows[i]["food_cat"]);
}
Any better solutions, suggestions and/or ideas are welcome.

Categories