Selenium: Cannot print values from different rows of a webtable - selenium

I am trying to print the values of the City column for different rows from the below table shown in the image.
I used the below code. My code prints "Dubai" 4 times instead of printing different cities. Can someone help me in fixing this?
System.setProperty("webdriver.chrome.driver","C:\\Selenium\\Drivers\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("http://toolsqa.com/automation-practice-table/");
WebElement body = driver.findElement(By.xpath("//*[#id='content']/table/tbody"));
List<WebElement> rows = body.findElements(By.tagName("tr"));
System.out.println(rows.get(0).findElement(By.xpath("//td[2]")).getText());
System.out.println(rows.get(1).findElement(By.xpath("//td[2]")).getText());
System.out.println(rows.get(2).findElement(By.xpath("//td[2]")).getText());
System.out.println(rows.get(3).findElement(By.xpath("//td[2]")).getText());
Table Image

Actually your code is correct, only problem with your xpath using for getting city element.
When you are going to find city name using xpath //td[2], your are searching actually second column every time but on whole page that's why you are getting same city name every time.
You need to provide .//td[2] xpath, because when you provided xpath with . it will search only element context otherwise it will search on document means on whole page, and according to whole page output is absolutely correct.
Now if you want simply print all cities try as below :-
List<WebElement> cities = driver.findElements(By.xpath("//*[#id='content']/table/tbody//td[2]"));
for(WebElement city : cities)
{
System.out.println(city.getText());
}

Try below code to print values of the City column:
List<WebElement> rows = driver.findElements(By.xpath("//*[#id='content']/tbody/tr"));
for(int row = 0; row < rows.size(); row++){
System.out.println(driver.findElement(By.xpath("//*[#id='content']/table/tbo‌​dy/tr[row]/td[2]")).getText());
}
Hope it helps!

Related

How to store and echo all ID's of present input fields by XPath in Selenium?

I am learning Selenium for automation testing and I am going through and trying to build up some test steps for basic account sign up on a website.
The process will involve grabbing all ID's of input fields within a form and then save those ID's to a variable(s) and echo all of those ID's back.
Currently my XPath looks something like:
//*[contains(concat(' ', normalize-space(#class), ' '), ' textField')]/descendant::input
Which, in Firebug highlights all of the input fields.
Now my question is, how would I go about saving the ID's of those input fields and echoing those back in Selenium for verification/debugging purposes?
I tried getting a better idea from: How to store the content/value of xpath?, but the only thing echo'd and saved in the temp variables is just the name of the variable I gave it.
(We'll call this variable "AllFormInputIDs")
Any and all help is super appreciated and any tips for more efficient XPath mark-up/code mark-up would be great! Thanks :)
You can follow the below process:
Find all the input tag elements in the page and store it in a list.
Iterate through the list, fetch the attribute id using getAttribute() method and store it in another Arraylist, say AllFormInputIDs as you mentioned.
Now you can iterate over the list of "AllFormInputIDs" to do any operation you want.
Below is the Java code snippet for the aforementioned process:
//Opening firefox driver instance, maximizing and assigining an implicit timeout of 20 seconds.
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
//Navigating to the site
driver.get("http://stackoverflow.com/questions/31574046/how-to-store-and-echo-all-ids-of-present-input-fields-by-xpath-in-selenium");
//Fetching all the elements with tag 'input' and putting in a List
List<WebElement> List_Inputs = driver.findElements(By.tagName("input"));
//Creating an ArrayList object
ArrayList<String> AllFormInputIDs = new ArrayList<String>() ;
//Iterating throught the input ids in List_Inputs and fetching the 'id' attribute
//where 'id' value is not an empty string
for(WebElement inputID: List_Inputs){
if(!inputID.getAttribute("id").equals(""))
AllFormInputIDs.add(inputID.getAttribute("id"));
}
//Iterating over AllFormInputIDs where the fetched id's of all Input tags are present
//and printing them
int i=1;
for(String id: AllFormInputIDs){
System.out.println("ID "+(i++)+": "+id);
}
Once you have found your element(s), you can use getAttribute method to retrieve the attached attribute of the element and store it.
Lets say we want to print all href links which starts with 'Stack' on this page inside footer:-
python code:
for element in driver.find_elements_by_xpath("//*[#id='footer']//../a[contains(.,'Stack')]"):
print(element.get_attribute('href'))
prints:
https://stackoverflow.com/ https://stackapps.com/
https://meta.stackexchange.com/ http://careers.stackoverflow.com/
Printing the id of the Ask Questions Button
print(driver.find_element_by_xpath("//*[text()='Ask Question']").get_attribute('id'))
nav-askquestion
Working example of a Python file for the same: GitHubFile

How to get the total search result counts using selenium

I want to get the result count when i do a search in amazon. Following is the scenario
Open a new browser instance
Navigate to the amazon.in
Type the search query in the text box
Click on the search button
Validate the web element displaying the number of search results against our expected value
public void searchTestOne(){
WebDriver driver = new FirefoxDriver();
driver.get("http://www.amazon.in");
driver.manage().window().maximize();
driver.findElement(By.id("twotabsearchtextbox")).sendKeys("Books");
driver.findElement(By.className("nav-submit-input")).click();
int result = driver.findElements(By.xpath(".//*[#id='atfResults']/ul[#id='s-results-list-atf']/li")).size();
System.out.println(result);
driver.close();
driver.quit();
}
From above code it displays only count of first page result like "16" where as there so many pages and total result is 2,000+.
Can anyone please suggest on this.
Webelment used to get total search result count is not correct. Correct element/tag is "h2" with id "s-result-count"
Below line should give you number of search result count:
String result = driver.findElement(By.id("s-result-count")).getText().split(" ")[2];
It seems like you are trying to fetch the number of books by counting the number of books enlisted. By this, you would have to navigate to each page, and increase your count accordingly. Rather, you can get the total number of results, alternatively, if you look at the top-left of the page as shown in the image below:
So, you can get the total count of results from this code as #Surya suggested:
String result = driver.findElement(By.id("s-result-count")).getText().split(" ")[2];
System.out.println(result);
Try this:
result = driver.findElements(By.xpath(".//*[#id='atfResults']/ul[#id='s-results-list-atf']/li")).count();

Locating images uniquely when img ids are dynamic and src same for multiple images

I have 3 custom dropdowns which open when clicked on "down arrow" image appended at the end, Code for the image is something like :
<img id="x-auto-2017" class="x-form-trigger x-form-trigger-arrow "
src="data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==">
Image id are dynamic and are in order of like 2017, 2018 etc. So I cannot use contains and identify them uniquely.
I want to get them clicked one by one and select value from the dropdown. Please help how to identify them uniquely.
Below code should work for you:
List<WebElement> elements = driver.findElements(By.xpath("//img[contains(#class,'x-form-trigger x-form-trigger-arrow']"));
System.out.println("Number of drop downs on the page: " + elements.size());
for (WebElement ele : elements) {
ele.click();
//Do what ever you want
}
Thanks for your response, I used the position qualifier [N] as suggested by #Marcus, though have to hit and trial a bit but writing manual xpath on Chrome console I got the following answer to my query.
driver.findElement(By.xpath("(//img[starts-with(#id,'x-auto-2')])[2]")).click();

How to find the element within element in selenium

I am creating a framework for the data validation using selenium. The issue I am struggling with is I want to locate the element "td"(html tag) within element "tr"(html tag) . This is the code I have written.
Iterator<WebElement> i = rows.iterator();
While(i.hasnext()){
List<WebElement> columns = row.findElements(By.tagName("td"));
for(WebElement s:columns)
{
System.out.println("columnDetails : "+s.getText().toString());
}
if(columns.isEmpty())
{
ElementNotFoundException e = new ElementNotFoundException("No data in table");
throw e;
}
Iterator<WebElement> j = columns.iterator();// does some other work
ClusterData c = new ClusterData(); // does some other work
ClusterDataInitializer.initUI(c, j, lheaders); // does some other work
CUIData.put(c.getCN(), c); // does some other work
}
Now the issue with this is:
I am trying to fetch the data from the rows(see table data) in arraylist and use that arraylist further. Currently whats happening is the data for column header is fetched at start of which I have no use.I only want the rows's data. I am not able to determine the proper way to collect the data of table rows only.
if xPath of the table will help you understand it properly then here are the details :
Table header xPath of cluster name column:
/html/body/table/tbody/tr[2]/td[2]/div[2]/div/div/div[2]/div/div/div[2]/div/div/div[2]/div/div/div/div/div/div[2]/div/div/div[2]/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]/div/div[2]
Table row (Table Data) xPath of test cluster 01:
/html/body/table/tbody/tr[2]/td[2]/div[2]/div/div/div[2]/div/div/div[2]/div/div/div[2]/div/div/div/div/div/div[2]/div/div/div[2]/div/div/div[3]/div[2]/div/table/tbody/tr/td[2]/div/div/a
Please let me know if you need anything else.
I am using the following code to extract row data from table.
List<WebElement> rows = getElement(driver,sBy,"table_div_id").findElements(By.tagName("tr"));
where sBy = By.id and table_div_id = id of div in which table is present. This extracts all the rows into arraylist and then i am using code to extract the row data into another arraylist. It is where I am stuck.
Each row from the table is in its own "table" tag so following things are not working :-
List<WebElement> rows = driver.findElements(By.xpath("//div[#id = 'table_div_id']//tr"));
List<WebElement> columns = row.findElements(By.xpath("./td"));
or the approach I used for the previous release of product i.e.
List<WebElement> columns = row.findElements(By.tagName("td"));
So, I used following approach which enabled me to capture all of the visible rows from the table.
List<WebElement> columns = row.findElements(By.xpath(".//table[#class='gridxRowTable']/tbody/tr"));
But after that I faced another issue that is since this table was implemented using dojo, the scrolling was impossible and Selenium was only able to capture the visible rows , so to overcome this I zoomed out in the browser using selenium. This is how i achieved my goal of getting the data.I believe others might have provided me answer if i would have shared some more details. Still , sorry about that and hope my answer helps you all.
instead of
List<WebElement> columns = row.findElements(By.tagName("td"));
try using
List<WebElement> columns = row.findElements(By.xpath("./td"));
Check if this helps. This should give you the td elements. If I have not understood your issue, let me know.
You can use this way-
driver.findElement(By.Xpath("//table[#id=\"table1\"]/tbody/tr[2]/td[1]"));
Regards,
Anuja
Do you have selenium IDE installed? Perform storeText operation on the row you want to retrieve, then xpath will get populated in IDE. There will be multiple xpaths; the most reliable is xpath:position, use that to capture your rows.
And use firebug for better visibilty of your AUT.
Firebug and Selenium IDE are the most basic component of Selenium Framework development.
You can manipulate xpath as you want.

Is by.id better than by.tagname?

I was working on reading mails from gmail using webdriver and in between I hit upon this difference between By.id and By.tagname.
I am trying to get access to a "table" whose id is ":pg". So I could
Either use By.id(":pg")
OR use By.tagname("table") and search for an element with id :pg
Here is the code for both cases.
By.id:
WebDriver webDriver = new FirefoxDriver();
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
webDriver = webDriver.switchTo().frame("canvas_frame");
WebElement table1 = webDriver.findElement(By.id(":pg"));`
Above code, I directly get the element which has id ":pg"
By.tagname:
WebDriver webDriver = new FirefoxDriver();
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
List<WebElement> tables = webDriver.findElements(By.tagName("table"));
for(WebElement table2: tables){
String id = table2.getAttribute("id");
System.out.println("id: "+ id);
if(id != null && id.equals(":pg")){
System.out.println("FOUND IT!!!");
}
}
Above code, I find all elements with the tagname of table and then see which one has the id ":pg".
Both these code snippets are essentially doing the same but using different ways(By.id or By.tagname). However, the first snippet of code which uses By.id always succeeds while the second snippet of code which uses By.tagname fails almost always. (It will work with additional waiting however)
Why is this difference between By.id and By.tagname?
Thanks,
Chris.
The :pg element is not present on the page initially.
Using By.Tag, selenium will not wait for the :pg element.
Because By.Id example is more specific, selenium will continue checking if the :pg element exists until the implicit wait (5 seconds) times out.
By.Tag is not specific at all. On findElements(By.tagName("table"), Selenium will return an array of all the tables that are present immediately after the page loads. As the :pg element is not present yet, it will not be in the array.
To answer your question, yes it is better to use By.Id because:
1. It is more specific.
2. Saves lines of code
3. Forces selenium to wait for the element to exist.
It is better to use By.Id according to your question.
By.tag is not used for specific data, it actually will search and return an array of all the tables with the specified tag name. On the other hand using id you can get the appropriate output for identifying/locating element.
Go for tag only if id, name or class is not specified and the best way can be By.cssSelector if no element is found.
Thanks