Verify all the options of a drop down in selenium c# - c#

I am writing selenium webdriver code in c#. I want to verify all the options of a drop down. I am using the following code. But its giving me an error for 'soc.options.text'. May I know where I am getting wrong?
SelectElement soc = new SelectElement(driver.FindElement(By.Id("soc_id_look")));
string[] drop = { "x----x", "Ra", "Ma", "sa", "ga", "ta" };
string[] actual = soc.Options.Text;
int n = drop.Length;
for (int i = 0; i < n; i++)
{
Console.Write(" " + drop[i]);
Assert.IsTrue(drop[i].Equals(actual[i]));
}

So I guess you are getting an error because soc.Options will return a collection of IWebElement's, and therefore .Text is not accessible.
Regardless of the error you are getting, the for loop can be condensed into a single LINQ statement:
Assert.IsTrue(drop.All(d => actual.Contains(d)));
http://msdn.microsoft.com/en-us/library/bb548541(v=vs.110).aspx
Determines whether all elements of a sequence satisfy a condition.
So it translates into "does every element within the "drop" array exist within the "actual" array? If so, return true, otherwise return false.
Now, to fix the inital error you were getting, you can, again, use LINQ, to translate it into a collection of string's:
IEnumerable<string> actual = soc.Options.Select(i => i.Text);
http://msdn.microsoft.com/en-us/library/bb548891(v=vs.110).aspx
Projects each element of a sequence into a new form.
So this would become "take each IWebElement within this collection, get the value of it's .Text property and return that." So we'd end up with a collection of string's.
We put it all together and end up with:
SelectElement soc = new SelectElement(driver.FindElement(By.Id("soc_id_look")));
string[] drop = { "x----x", "Ra", "Ma", "sa", "ga", "ta" };
IEnumerable<string> actual = soc.Options.Select(i => i.Text);
Assert.IsTrue(drop.All(d => actual.Contains(d)));
However, just as a note, if you get errors (whether compiler or runtime) you should post the entire error, along with the entire stack trace (if there is one). It is near impossible to help when someone says "I get an error" and we've got no idea whatsoever on what error it is. Just a friendly tip to help you get the best out of StackOverflow.
I can guess the error you got was probably something along the lines of IEnumerable<IWebElement> does not contain a definition for ".Text".

I think this will work:
IList<IWebElement> options = soc.Options;
Assert.Equals(options.Count, drop.Length);
foreach (IWebElelent option in options)
{
Console.Write(" " + drop[i]);
Assert.IsTrue(drop.Contains(option.Text));
}

Related

Check if the value exists in a dropdown

I have a dropdown that contains Subjects.
What I did, I use the code below to get the values on that dropdown.
IList<IWebElement> allOptions = check.Options;
Then I declare a string that will handle all the values I have to verify if these values exist on that dropdown.
string[] subject = "Math", "Science", "History", "Calculus", etc...
I loop them to get how many subjects I have to check if they exist on the dropdown then verify it using Contains.
if (allOptions.Contains(subject[i]))
{
exist = true;
}
However, I am getting an error that cannot convert a string to OpenQA.Selenium.IWebElement.
Anyone has idea how to fix it?
Thank you.
You can use LINQ for this. Basically this code:
if (allOptions.Contains(subject[i]))
{
exist = true;
}
Can be replaced by a single line:
exist = allOptions.Any(x => x.Text == subject[i]);
Basically this code just checks if any element in the allOptions list has Text that matches subject[i]. If true, exist is now true, if false exist is now false.
Indeed, you cannot do that directly. The IWebElement contains a string property named Text, which is what you need to filter on. Like so:
var foundSubjects = allOptions.Where(o => subject.Contains(o.Text));
If you just need to find out if ALL the options are found in the subject array, do:
var optionsAreValid = allOptions.All(o => subject.Contains(o.Text));
Alternatively you could use Any to determine if at least one option exists in the subject array:
var isThereAValidOption = allOptions.All(o => subject.Contains(o.Text));
Try looping through the IList<IWebElement> instead:
int subjectCount = 0;
foreach (IWebElement element in allOptions)
{
if (subject.Contains(element.Text))
{
subjectCount++;
}
}
Use the Text property of the WebElement. it may be work for you

I'm using the property findelements with selenium and C#, but it keeps giving the same error

This is a part of the code that i was trying to use to get the respective elements, but it keeps giving me the following error:
System.Collections.ObjectModel.ReadOnlyCollection`1[OpenQA.Selenium.IWebElement]or
others identical
This is also shown in a datagridview, in her rows.
IList<IWebElement> ruas = Gdriver.FindElements(By.ClassName("search-title"));
String[] AllText = new String[ruas.Count];
int i = 0;
foreach (IWebElement element in ruas)
{
AllText[i++] = element.Text;
table.Rows.Add(ruas);
}
First thing is: as far as I understand the elements you are talking about are not contained in table. Its a list: <ul class="list-unstyled list-inline">... (considering the comment you left with site link)
If you want to find those elements you can use the code below:
var elements = driver.FindElements(By.CssSelector("ul.list-inline > li > a"));
// Here you can iterate though links and do whatever you want with them
foreach (var element in elements)
{
Console.WriteLine(element.Text);
}
// Here is the collection of links texts
var linkNames = elements.Select(e => e.Text).ToList();
Considering the error you get, I may assume that you are using DataGridView for storing collected data, which is terribly incorrect. DataGridView is used for viewing data in MVC application. There is no standard Selenium class for storing table data. There are multiple approaches for this, but I can't suggest you any because I don't know your what you are trying to achieve.
Here is how i answered my own question:
IList<string> all = new List<string>();
foreach (var element in Gdriver.FindElements(By.ClassName("search-title")))
{
all.Add(element.Text);
table.Rows.Add(element.Text);
}

IEnumerable Where filtering occuring without actually being called

I'm using HtmlAgilityPack to parse a page of HTML and retrieve a number of option elements from a select list.
The GvsaDivisions is a method that returns raw html from the result of a POST, irreverent in the context of the question
public IEnumerable<SelectListItem> Divisions(string season, string gender, string ageGroup)
{
var document = new HtmlDocument();
var html = GvsaDivisions(season);
document.LoadHtml(html);
var options = document.DocumentNode.SelectNodes("//select//option").Select(x => new SelectListItem() { Value = x.GetAttributeValue("value", ""), Text = x.NextSibling.InnerText });
var divisions = options.Where(x => x.Text.Contains(string.Format("{0} {1}", ageGroup, gender)));
if (ageGroup == "U15/U16")
{
ageGroup = "U15/16";
}
if (ageGroup == "U17/U19")
{
ageGroup = "U17/19";
}
return divisions;
}
What I'm observing is this... once the options.Where() is executed, divisions contains a single result. After the test of ageGroup == "U15/U16" and the assignment of ageGroup = "U15/16", divisions now contains 3 results (the original 1, with the addition of 2 new matching the criteria of the new value of ageGroup
Can anybody explain this anomaly? I expected to make a call to Union the result of a new Where query to the original results, but it seems it's happening automagically. While the results are what I desire, I have no way to explain how it's happening (or the certainty that it'll continue to act this way)
LINQ queries use deferred execution, which means they are run whenever you enumerate the result.
When you change a variable that is being used in your query, you actually are changing the result of the next run of the query, which is the next time you iterate the result.
Read more about this here and here:
This is actually by-design, and in many situations it is very useful, and sometimes necessary. But if you need immediate evaluation, you can call the ToList() method at the end of your query, which materializes you query and gives you a normal List<T> object.
The divisions variable contains an unprocessed enumerator that calls the code x.Text.Contains(string.Format("{0} {1}", ageGroup, gender)) on each element in the list of nodes. Since you change ageGroup before you process that enumerator, it uses that new value instead of the old value.
For example, the following code outputs a single line with the text "pear":
List<string> strings = new List<string> { "apple", "orange", "pear", "watermelon" };
string matchString = "orange";
var queryOne = strings.Where(x => x == matchString);
matchString = "pear";
foreach (var item in queryOne)
{
Console.WriteLine(" " + item);
}
I'm thinking along the same lines as Travis, the delayed execution of linq.
I'm not sure if this will avoid the issue, but I generally put my results into an immediate collection like this. With my experience it seems once you shove the results into a real defined collection I believe it may not be delayed execution.
List<SelectListItem> options = document.DocumentNode.SelectNodes("//select//option").Select(x => new SelectListItem() { Value = x.GetAttributeValue("value", ""), Text = x.NextSibling.InnerText }).Where(x => x.Text.Contains(string.Format("{0} {1}", ageGroup, gender))).ToList<SelectListItem>();

Getting number of ITEMS in an array C#

I need to insert a string (from one window(QueryBuilder)) into an array(of another window(Main)).
In the Main i have a method as
public void DisplayCalcQuery(string argFromQueryBuilder)
{
int itemsInUserBuiltQueries = UserBuiltQueries.Count();
UserBuiltQueries[itemsInUserBuiltQueries] = argFromQueryBuilder.ToString();
//displayng the user built query(queries) on the stack panel meant to display it.
foreach (string query in UserBuiltQueries)
{
CheckBox checkQueries = new CheckBox() { Content = query };
stackPanel1.Children.Add(checkQueries);
checkboxes.Add(checkQueries);
}
}
Where UserBuiltQueries is declared as
string[] UserBuiltQueries;
However when from the other window i do
backscreen.DisplayCalcQuery(ttextBox1.Text.ToString()); //where backscreen is the Main
The argument is passed well but i get an error as
{"Value cannot be null.\r\nParameter name: source"}
What did I do wrong ?
These lines are wrong
int itemsInUserBuiltQueries = UserBuiltQueries.Count();
UserBuiltQueries[itemsInUserBuiltQueries] = argFromQueryBuilder.ToString();
Arrays start at index zero and end at index (Count - 1), so, if UserBuiltQueries.Count() returns 10 you could use indexes from 0 to 9. Essentially, using index 10, you are adding a new string outside the end of the array.
However, if your requirements force you to expand the array, it is better and more easy to code if you use a List<string> instead. Adding new elements will be a lot more easier and you could still use the List as an Array for common tasks.
List<string> UserBuiltQueries = new List<string>();
.....
public void DisplayCalcQuery(string argFromQueryBuilder)
{
UserBuiltQueries.Add(argFromQueryBuilder);
//displayng the user built query(queries) on the stack panel meant to display it.
foreach (string query in UserBuiltQueries)
{
CheckBox checkQueries = new CheckBox() { Content = query };
stackPanel1.Children.Add(checkQueries);
checkboxes.Add(checkQueries);
}
}
By the way, you should stop to unnecessarily convert a string to a string. You pass a ttextBox1.Text.ToString() but ttextBox1.Text is already a string. Inside the method the parameter argFromQueryBuilder is already a string and there is no need to convert to a string
Instead of using string[] for UserBuildQueries, use List. When you need it as an array, you can simply say: UserBuildQueries.ToArry()
Rewrite the function to
public void DisplayCalcQuery(string argFromQueryBuilder)
{
UserBuiltQueries.Add(argFromQueryBuilder.ToString());
//displayng the user built query(queries) on the stack panel meant to display it.
foreach (string query in UserBuiltQueries)
{
CheckBox checkQueries = new CheckBox() { Content = query };
stackPanel1.Children.Add(checkQueries);
checkboxes.Add(checkQueries);
}
}
In c# but I think in all programming language indexis start from 0:
so if an array has length or count =1 the index is 0 array[0], array.lenght==1
int itemsInUserBuiltQueries = UserBuiltQueries.Count()-1;
UserBuiltQueries[itemsInUserBuiltQueries] = argFromQueryBuilder.ToString();
And double check that your array is initialized before using it!

Find a string list whether containing same element more than once

I am writing my own specific web crawler for product selling websites. Due to their very bad coding nature i get with getting urls pointing same page.
Example one
http://www.hizlial.com/bilgisayar/bilgisayar-bilesenleri/bilgisayar/yazicilar/samsung-scx-3200-tarayici-fotokopi-lazer-yazici_30.033.1271.0043.htm
For example the page above is same as below
http://www.hizlial.com/bilgisayar-bilesenleri/bilgisayar/yazicilar/samsung-scx-3200-tarayici-fotokopi-lazer-yazici_30.033.1271.0043.htm
As you can see it contains 2 "bilgisayar" element when you split via '/' character
So what i want is i want to split urls like this
string[] lstSPlit = srURL.Split('/');
After that check that whether that list contains same element more than once or not. Any element. If contains any element i will skip the url because i would have already have the real url extracted from some other page. So what is the best way of doing this ?
Longer but working version
string[] lstSPlit = srHref.Split('/');
bool blDoNotAdd = false;
HashSet<string> splitHashSet=new HashSet<string>();
foreach (var vrLstValue in lstSPlit)
{
if (vrLstValue.Length > 1)
{
if (splitHashSet.Contains(vrLstValue) == false)
{
splitHashSet.Add(vrLstValue);
}
else
{
blDoNotAdd = true;
break;
}
}
}
if (list.Distinct().Count() < list.Count)
This ought to be faster than grouping. (I haven't measured)
You can make it even faster by writing your own extension method that adds items to a HashSet<T> and returns false immediately if Add() returns false.
You can even do that using a wicked shorthand:
if (!list.All(new HashSet<string>().Add))
if(lstSPlit.GroupBy(i => i).Where(g => g.Count() > 1).Any())
{
// found more than once
}

Categories

Resources