How to use the FindElements command correctly? - c#

Below I have three dive tags that all have the same class:
<div class="confirmation-price-summary__price-label confirmation-price-summary__price-label--with-dropdown">(2) Seats</div>
<div class="confirmation-price-summary__price-label confirmation-price-summary__price-label--with-dropdown">(2) Meals</div>
<div class="confirmation-price-summary__price-label confirmation-price-summary__price-label--with-dropdown firefinder-match">(1) Extra Baggage</div>
I create a variable to point to the all of those class elements via xpath in my 'confirmationResponsiveElements.cs' page:
public static By TravelEssentialsBasketLabels => By.XPath("//*[#class='confirmation-price-summary__price-label confirmation-price-summary__price-label--with-dropdown']");
I want to use the 'FindElements' method to find all of these elements and then assert that they contain 'Seats', 'Meals' and 'Extra Baggage'. However I am not sure how to use this correctly as it's giving me the red line of death:
public void TravelEssentialsLabelsSideBasket()
=> _driver.FindElements(ConfirmationResponsiveElements.TravelEssentialsBasketLabels).ToString();
What is the corret way to use FindElements and also, how can Assert.IsTrue should be written if I want to check that it contains 'Seats' , 'Meals' and 'Extra Baggage'?
Thanks

List<string> actualoptions = new List<string>();
List<string> expectedoptions = new List<string>();
expectedoptions.Add("Seats");
expectedoptions.Add("Meals");
expectedoptions.Add("Extra Baggage");
ReadOnlyCollection<IWebElement> links = driver.FindElements(By.XPath("//*[#class='confirmation-price-summary__price-label confirmation-price-summary__price-label--with-dropdown']"));
foreach(IWebElement link in links)
{
string text = link.Text;
actualoptions.Add(text);
}
//then you compare this list with expected value
if(String.SequenceEqual(actualoptions ,expectedoptions)){
console.write("matching");
else
console.write("not matching");

Related

Print text of elements from an list in C#

I have to print all the text of the web elements, so i am storing the web elements in list "test" and then getting text of each web element and keep them adding to other list "Title".
Now when i am trying to print all the elements of list "Title".But only the text of 1st element is printed.
Please help me to find where i am going wrong.
public void PrintText()
{
var Title = new List<string>();
IList <IWebElement> test=Controls.GetWebElementList(X-path);
foreach (var g in test)
{
Title.Add(Controls.GetText(x-path));
}
foreach (var h in Title)
{
Console.WriteLine(h);
}
}
It's not that clear how Controls.GetWebElementList() is defined.
Ideally to extract the texts you have to induce WebDriverWait for VisibilityOfAllElementsLocatedBy() and you can use the following Locator Strategy:
IList <IWebElement> test = new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.XPath("X-path")));
Your code looks fine.
Try to verify the first list to print their values.
And then run again, maybe your first line had only one value.

Verify Order Of HTML Elements With Attribute Values Such as Class="Group0-Item1" Class="Group0-Item2" Class="Group1-Item1"

In my Selenium/C#/NUNIT project, I need to find a way to validate the order (top down hierarchy of a page's HTML) for a group of HTML elements (as well as the elements contained within those groups). These are my elements that show inside my page's HTML...
<div class="gapBanner-banner-order1-group0"></div>
<div class="gapBanner-banner-order1-group1"></div>
<div class="gapBanner-banner-order1-group2"></div>
<div class="gapBanner-banner-order2-group2"></div>
The validation I want to perform should be able to catch the following bugs:
Bug 1: The groups are not in order within the page's HTML. One of the elements that is in group1 appears first in the HTML before group0...
<div class="gapBanner-banner-order1-group1"></div>
<div class="gapBanner-banner-order1-group0"></div>
<div class="gapBanner-banner-order1-group2"></div>
<div class="gapBanner-banner-order2-group2"></div>
Bug #2: The elements WITHIN each group are not in order within the page's HTML. Group2-Order2 appears before Group2-Order1 within the HTML
<div class="gapBanner-banner-order1-group0"></div>
<div class="gapBanner-banner-order1-group1"></div>
<div class="gapBanner-banner-order2-group2"></div>
<div class="gapBanner-banner-order1-group2"></div>
The below is what I have coded so far, but it is definitely not going to do the job, not to mention, it is very messy. I cant figure out what kind of logic I need for this
/// 5. Verify the correct order of elements in which they appear inside the HTML
List<IWebElement> CustomPageHTMLComponents = Browser.
FindElements(By.XPath("//div[contains(#class, 'group')")).ToList();
List<IWebElement> uniqueGroups = new List<IWebElement>();
// Get the unique groups
for (int i = 0; i < CustomPageHTMLComponents.Count; i++)
{
IWebElement currentComponent = Browser.FindElements(By.XPath("//div[contains(#class, 'group')"))[i];
string toBeSearched = "group";
string currentComponenetClassAttributeValue = currentComponent.GetAttribute("class");
int x = currentComponenetClassAttributeValue.IndexOf(toBeSearched);
string groupNumber = currentComponenetClassAttributeValue.Substring(x + toBeSearched.Length);
if (groupNumber == i.ToString())
{
uniqueGroups.Add(currentComponent);
}
}
// Some kind of logic to verify everything???
for (int i = 0; i < Page.CustomPageHTMLComponents.Count; i++)
{
IWebElement currentComponent = Browser.FindElements(By.XPath("//div[contains(#class, 'group')"))[i];
string toBeSearched = "group";
string currentComponenetClassAttributeValue = currentComponent.GetAttribute("class");
int x = currentComponenetClassAttributeValue.IndexOf(toBeSearched);
string groupNumber = currentComponenetClassAttributeValue.Substring(x + toBeSearched.Length);
Assert.AreEqual(groupNumber, i.ToString());
}
There are probably a number of ways to do this. This is the first way I came up with...
Grab all the class names from the desired elements and store them in string array #1
Make a copy of string array #1 and sort it
Compare the two arrays and if they are equal, then they were sorted to start with
I've checked the HTML you provided for the bugs you'd like to catch and it catches them all. The one issue I can think of is if you get more than 9 orders or groups the sorting will not be what you want because it's alpha order not numerical order, e.g. 1, 10, 2, ... instead of 1, 2, ... 10.
// capture the class names from the desired classes
string[] elements = _driver.FindElements(By.CssSelector("div[class^='gapBanner-banner-']")).Select(e => e.GetAttribute("class")).ToArray();
// make a copy of the array
string[] sortedElements = new string[elements.Length];
elements.CopyTo(sortedElements, 0);
// sort the copy
Array.Sort(sortedElements);
// compare the arrays for order using NUnit CollectionAssert
CollectionAssert.AreEqual(elements, sortedElements, "Verify ordering of elements");

How to parse text from anonymous block in AngleSharp?

I'm parsing site content using AngleSharp and i've got an issue with anonymous block.
See the sample code:
var parser = new HtmlParser();
var document = parser.Parse(#"<body>
<div class='product'>
<a href='#'><img src='img1.jpg' alt=''></a>
Hello, world
<div class='comments-likes'>1</div>
</div>
<div class='product'>
<a href='#'><img src='img2.jpg' alt=''></a>
Yet another helloworld
<div class='comments-likes'>25</div>
</div>
<body>");
var products = document.QuerySelectorAll("div.product");
foreach (var product in products)
{
var productTitle = product.Text();
productTitle.Dump();
}
So, productTitle contains numbers from div.comments-likes, output is:
Hello, world 1
Yet another helloworld 25
I've tried something like product.FirstElementChild.NextElementSibling.Text(); but next sibling for link element is div.comments-likes, not anonymous block. It shows:
1
25
So, anonymous blocks are skipped. :(
The best workaround i've found is deleting all preventing blocks, for my example:
product.QuerySelector(".comments-likes").Remove();
var productTitle = product.Text().Trim();
Is better way for parsing text from anonymous block?
Text is modeled as a TextNode, it is a type of node beside element, comment node, processing instruction, etc. That's why NextElementSibling you tried didn't include the text in the result since it intended to return elements only, as the name suggests.
You can get text nodes located directly within product div by traversing through the div's ChildNodes and then filter by NodeType, for example :
var products = document.QuerySelectorAll("div.product");
foreach (var product in products)
{
var productTitle = product.ChildNodes
.First(o => o.NodeType == AngleSharp.Dom.NodeType.Text
&& o.TextContent.Trim() != "");
Console.WriteLine(productTitle.TextContent.Trim());
}
dotnetfiddle demo
Notice that newlines between elements are also text nodes, so we need to filter those out in the demo above.

If string in list occurs in string, then add to list

had a look around and found many similar questions but none matching mine exactly.
public bool checkInvalid()
{
invalidMessage = filterWords.Any(s => appmessage.Contains(s));
return invalidMessage;
}
If a string is found that matches a string in the list the boolean invalidMessage is set to true.
After this though I would like to be able to add each string found to a list. is there a way I can do this using .Contains() or can someone recommend me another way to go about this?
Many thanks.
Well, from your description, I thought here is what you want:
// Set of filtered words
string[] filterWords = {"AAA", "BBB", "EEE"};
// The app message
string appMessage = "AAA CCC BBB DDD";
// The list contains filtered words from the app message
List<string> result = new List<string>();
// Normally, here is what you do
// 1. With each word in the filtered words set
foreach (string word in filterWords)
{
// Check if it exists in the app message
if (appMessage.Contains(word))
{
// If it does, add to the list
result.Add(word);
}
}
But as you said, you want to use LINQ, so instead of doing a loop, you can do it like this:
// If you want to use LINQ, here is the way
result.AddRange(filterWords.Where(word => appMessage.Contains(word)));
If what you want is to gets the words in filterWords that are contained in appmessage you can use Where:
var words = filterWords.Where(s => appmessage.Contains(s)).ToList();

How to find multiple elements on a page in selenium?

I have multiple input HTML tags on same page having same id and name or class,
Now How should I find 2nd or 3rd.. etc input. I can work with arrays so Do we have some function which will return all the textBox(input tag) from that page.
First you create a list with FindElements, then you can iterate through that list. For example:
var allTextBoxes = driver.FindElements(By.TagName("input"));
foreach(var textBox in allTextBoxes)
{
textBox.DoSomething();
}
You can use a for-loop as well:
for(int i = 0; i < allTextBoxes.Count; i++)
{
allTextBoxes[i].DoSomething();
}
Or if you want a specific Element, in example the 3rd:
allTextBoxes[2].DoSomething();
Expanding on Anaxi's answer,
If you are using the PageObject framework you can do it like this and set the FindsBy attribute on a property:
[FindsBy(How = How.Id, Using = "YourId")]
public IList<IWebElement> ListOfWebElements { get; set; }
i dont know about selenium... but to select element of html page you can use HtmlAgilityPack..
HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(#"http://example.com");
HtmlNode node = doc.DocumentNode.SelectNodes("//div[#class='your_class_name']");
it will return a list of node that contains your_class_name.. then find and use the one you want.
to select all the input tags from that page you can use
foreach (var input in doc.DocumentNode.SelectNodes("//input"))
{
//your logic here
}
hope it helps..
In C# I use FindElements then ElementAt():
var foo= Driver.FindElements(By.XPath("//div[#class='your_class_name']"));
var foo2= foo.ElementAt(1);
If it's 10 elements with the same ID (which is HORRIBLE) and I'd like to grab the 8th element, I just use ElementAt(8); (or index 7 or however you're set up).
It's a tough call. I'd much rather have them fix the code but in some cases that's just not going to happen... at least not in the near future.
Hope this helps.

Categories