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.
Related
I'm trying to spy a web site with Selenium and C# to watch if new items appears on it.
Inside this web site, I have a list of <div class="myClass"> elements displayed like a table with many sub divs.
Periodically, I read all displayed divs and check if a new one is present.
But the number of divs is limited and when a new element appears, the oldest one is removed and it making an issue on my code.
Example: The max number of items is 3.
I get 3 items A,B,C.
a new item D appears.
I read the 3 displayed items: when I'm reading all sub div of D, a new item E comes and D is moved and I get an error like "Element is no longer attached to the DOM"
I get this error because the reading of all D sub divs is too long.
I'm getting the webelement using FindElement(By.Name("elemName")
There is a way to keep the element in memory even if this one is move or removed from the DOM?
Thanks!
This is an interesting problem that I've run into in the past. Through a few frustrating debugging sessions, I found that my WebElement objects were dynamically changing based on what was visible on the page. I would retrieve a List<WebElement>, change something on the page, and notice that my List<> would actually change with the contents on the page.
To answer your question.....I'm not totally sure if this is possible, to store the WebElement itself, without removing the old div as you mentioned.
The only workaround I would suggest to this is creating your own Element class and assigning WebElements to this class so you can basically create your own "cache" of elements.
Here's a little sample:
public class Element
{
public string TagName { get; set; }
public string Text { get; set; }
public bool Displayed { get; set; }
// any other attributes you want to store here
}
public List<Element> StoreWebElements(List<IWebElement> seleniumElements)
{
var result = new List<Element>();
foreach (var elem in seleniumElements)
{
result.Add(new Element { TagName = elem.TagName,
Text = elem.Text,
Displayed = elem.Displayed
};
}
}
// your code
var divList = Driver.FindElements(By.Name("elemName"));
// "store" the elements
var cachedElements = StoreWebElements(divList);
// do something on the page to change it
// divList will change, but cachedElements will stay the same.
It's a bit of a hacky solution, but I personally never found a workaround to the issue that you have described. I would be curious to see if anyone else has an explanation or better solution for this.
I am automating some website and I got stuck on such a case. I have a list created, everything is great for me, it has 24 elements. These are products from the store, containing their picture, name, price, etc. But now I need to take two things from the first element and display in the console, namely name and price. Is anyone able to suggest something? I sit and thinks but nothing comes out. All I managed to do was send everything for 1 item.
I tried resolve that with some Linq but without success.
public List<string> ListOfElements()
{
var elements = new List<string>();
IReadOnlyCollection<IWebElement> listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
foreach (IWebElement element in listElements)
{
elements.Add(element.Text);
}
return elements;
}
public void DisplayFirstElement()
{
var firstElement = ListOfElements();
Console.WriteLine(firstElement[0]);
}
I want get name and price of first element and then assert that price for that is greater than 10.
You´re flattening all the elements properties into a single collection of strings. Thus you´re losing any relationship between those strings. It´s hard to say what the 22rd element within thhat list actually is: is it a price? A name? Something completey different? To which item does it actually belong?
Instead you should just return a list of entities and then print the properties of the very first entitity:
public List<IWebElement> ListOfElements()
{
var elements = new List<string>();
return listElements = _driver.FindElements(By.CssSelector(".category-list div[class='cat-prod-row js_category-list-item js_clickHashData js_man-track-event ']");
}
public void DisplayFirstElement()
{
var allElements = ListOfElements();
var firstElement = allElements.First();
Console.WriteLine("FirstName: " + firstElement.Name + " Price: " + firstElement.Price);
}
Of course this assumes your IWebElement has a Name- and a Price-property.
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");
I have a bunch of divs. I am looping thru them using their class name: col-lg-3. In each of the divs by the class name above, I have xpaths like the ones below. I need to pick out the string value at td[4]
.//*[#id='item-186951']/div[1]/table/tbody/tr[6]/td[4]
.//*[#id='itemPNS18-152951']/div[1]/table/tbody/tr[6]/td[4]
.//*[#id='itemXYZ-8152951']/div[1]/table/tbody/tr[6]/td[4]
.//*[#id='item11641551']/div[1]/table/tbody/tr[6]/td[4]
.//*[#id='itemAPS12641']/div[1]/table/tbody/tr[6]/td[4]
This part is the one that is changing in every element [#id='{dynamically-changing-id}'], with the rest being constant. How do I loop over this? At the moment I am trying this but I only get the first item (understandably)
//get all divs on page
var elements = ...FindElements(By.ClassName("col-lg-3"));
//for each div found
foreach(var e in elements)
{
//get text at xpath
string str = e.FindElement(By.XPath(".//*[#id='item-186951']/div[1]/table/tbody/tr[6]/td[4]"));
}
Im using Selenium 2.53
You can check that id attribute starts with "item":
var elements = ThisPage.FindElements(By.XPath(".//*[starts-with(#id, 'item')]/div[1]/table/tbody/tr[6]/td[4]"))
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.