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.
Related
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/tbody/tr[row]/td[2]")).getText());
}
Hope it helps!
I am testing out Selenium recently to see if it can recognize my web app better than QTP. So far it seems doing quite well. I ran into a problem trying to find an element within the table element. Some how I was not able to find master table but not the rows within the table.
This is how the table looks like
The code below works fine...
WebElement BaseTable = driver.findElement(By.id("table_simpleBrowser|type=TradingInstrumentReport|!browser"));
Where as the code below does not...
BaseTable = driver.findElement(By.id("table_simpleBrowser|type=TradingInstrumentReport|!browser_tr_1"));
or
BaseTable = driver.findElement(By.className("even status_DEFAULT"));
or
WebElement BaseTable = driver.findElement(By.id("table_simpleBrowser|type=TradingInstrumentReport|!browser"));
BaseTable = BaseTable.findElement(By.className("even status_DEFAULT"));
Can someone please help to show me how I can retrieve the a certain value in the table by finding the element in certain row/column in the table?
Thanks.
even and status_DEFAULT are actually two classes of this web element. By.className() receives only one class as parameter. It should be
findElement(By.className("even"));
// or
findElement(By.className("status_DEFAULT"));
To find element by the two classes use By.cssSelector()
findElement(By.cssSelector(".even.status_DEFAULT")); // note the dot before each class name
However it seems that its not unique enough. I recommend you search by id which contains browser_tr_1
findElement(By.cssSelector("[id*=`browser_tr_1`]"));
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
I have to test some complicated web service using Selenium.
Problem is that ids of elements are changing from session to session.
For example there is bunch of inputs each have id with prefix textf_id_DComboBox_ and ends with a consecutive numbers, starting number is random (session dependent).
Those inputs doesn't have a common parent so nth-child doesn't work.\
I can find first input by using selector: css=input[id^='textf_id_DComboBox_'] but I have no idea how to find next items (1-7) which match this selector.
I've found some suggestions on stackoverflow that xpath selector should be used, but I was unable to adopt examples for my use case.
Update:
I have also alternative selector which captures first input: css=td.DForm_treeGridNoWrap input.
You can use this XPath in order to select all inputs that contain a common id:
string comboBoxXPath = "//input[contains(#id, 'textf_id_DComboBox')]";
List<WebElement> comboBoxElements = driver.findElements(By.XPath(comboBoxXPath));
At this point, you can iterate through the entire collection, or you can select which one you'd like to interact with by using an index:
comboBoxElements[1]
comboBoxElements[2]
comboBoxElements[3]
etc...
Well, that descrption does not help that much. You can try these tricks:
You can call findElement on WebElement This trick will probably not work, because those IDs do not have common parent. But if they are wrapped, say, in table, you can find the table first:
WebElement table = driver.findElement(By.id("the-table"));
And then to find all input in such table:
List<WebElement> inputs = table.findElements(By.tagName("input"));
Install Selenium IDE to your firefox and try record testcase by using it. You can play with target in Selenium IDE.
Dirty approach
List<WebElement> allInputs = driver.findElements(By.tagName("input"));
Will find all inputs in such page.
Footnote: The code is Java and driver variable is considered as healthy instance of WebDriver
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