We have a website that is built upon a ton of tables. Each cell within the rows is clickable. I am working on a way to dynamically build the cssSelector info by providing the table name and value I want to click on. I am getting close (I think).
Using the practice table at ToolsQA, say I want to build the cssSelector for the value "Taiwan".
It's cssSelector is: .tsc_table_s13 > tbody:nth-child(4) > tr:nth-child(3) > td:nth-child(2)
I am iterating through the table and have successfully been able to enter the cell using the value ("Taiwan") I specified, however, I'm not sure how to get the value of the row and column it is currently on.
Here is the code I am using so far:
driver.get("http://toolsqa.com/automation-practice-table/");
String table = ".tsc_table_s13 > tbody:nth-child(4)";
String cellValue = "Taiwan";
getCell(table, cellValue);
// Get the cell of a particular value
public static void getCell(String table, String value) throws IOException{
// Grab the table
WebElement tableName = driver.findElement(By.cssSelector(table));
// Now get all the TR elements from the table
List<WebElement> allRows = tableName.findElements(By.tagName("tr"));
// And iterate over them, getting the cells
for (WebElement row : allRows) {
List<WebElement> cells = row.findElements(By.tagName("td"));
// Print the contents of each cell
for (WebElement cell : cells) {
// System.out.println(cell.getText());
if (cell.getText().equals(value))
{
String cellValue = table + " > tr:nth-child(" + row. + ") > td:nth-child(" + cell + ")";
System.out.println(cellValue);
} // end if text equals
} // end for loop for cells
} // end for loop for all rows
} // end getCell function
So here's a quick example of how you can use XPath to find text in a table and get a reference to the element. You provide the text to search for and it gets inserted into an XPath. That XPath below, searches for a TD that contains that text. This is just a simple case. If you have a lot of repetitive text in your table, you'll have to post some examples so that I can update the code to take that into account.
String searchText = "China";
driver.get("http://toolsqa.com/automation-practice-table/");
WebElement e = driver.findElement(By.xpath("//td[text()='" + searchText + "']"));
System.out.println(e.getText()); // you can get the text in the cell
System.out.println(e.getAttribute("outerHTML")); // you can get the HTML of the TD
e.click(); // you can click the element also but in this case it won't do anything since it's just a TD with text
Related
driver.get("https://www.leafground.com/dynamicgrid.xhtml");
//count column
List<WebElement> column = driver.findElements(By.tagName("th"));
System.out.println(column.size());
//row
List<WebElement> row = driver.findElements(By.tagName("tr"));
System.out.println(row.size()/2);
//return value of a customer
String text = driver.findElement(By.xpath("//td[normalize-space()='Costa Jennifer']//td[3]")).getText();
System.out.println(text);
What I'm trying to do is to get the activity value for Costa Jennifer value. But I'm getting:
Unable to locate the element.
You need to improve your locators.
This will give you the table rows:
List<WebElement> rows = driver.findElements(By.xpath("//tbody//tr[#role='row']"));
System.out.println(rows.size());
To get activity value of some user you can locate the row by user name and then locate proper td cell value. As following:
String activity = driver.findElement(By.xpath("//tr[contains(.,'Munro Leon')]//td[4]")).getText();
System.out.println(activity);
In my code, I try to find all elements with a specific name, then try taking each elements' descendant and get its title, link and price. The price I'm having issues with because it sticks to the price tag of the first element from the WebElements list.
List<WebElement> autos = driver.findElements(By.xpath("//section[contains(#class ,'ui-search-results')]/ol/li//a[#class = 'ui-search-result__content ui-search-link']"));
for(WebElement auto : autos) {
String model = auto.getAttribute("title");
String page = auto.getAttribute("href");
String price = auto.findElement(By.xpath("//span[#class = 'price-tag-fraction']")).getText();
System.out.println(model + page + price);
}
Console is printing model and page just fine but the price is always the same one. I already tested the site and there is a price-tag-fraction per element.
When you use XPath and want to start searching from a specific element, you need to add a . to the start of the XPath. In your case
"//span[#class = 'price-tag-fraction']"
becomes
".//span[#class = 'price-tag-fraction']"
Your updated code
List<WebElement> autos = driver.findElements(By.xpath("//section[contains(#class ,'ui-search-results')]/ol/li//a[#class = 'ui-search-result__content ui-search-link']"));
for(WebElement auto : autos) {
String model = auto.getAttribute("title");
String page = auto.getAttribute("href");
String price = auto.findElement(By.xpath(".//span[#class = 'price-tag-fraction']")).getText();
System.out.println("Model: %s, Page: %s, Price: %s".formatted(model, page, price));
}
NOTE: I changed your print statement to make it easier to read. You could also write these to a CSV file and then open them later in Excel, etc. as a table.
I would like to catch a text within the field and be able to click on that element. It extracts all the elements' texts into log when I use the following:
String text;
text = HomePageFields.TableOneColumn(driver).getText();
System.out.println("Table One Column contains following:\n" + text);
The TableOneColumn xpath is on different class:
public static WebElement TableOneColumn(WebDriver driver) throws IOException {
element = driver.findElement(By.xpath("//div[contains(#eventproxy,'isc_QMetricsView_0')]/div[1]/div[1]/div[1]/div[1]/div[1]/div[contains(#style,'position')]/div"));
return element;
I tried to use:
HomePageFields.TableOneColumn(driver).findElement(By.linkText("RFI Overview")).click();
But it gives an error saying won't find the element.
Here is the html link to that particular text. But other text contain in the same tag but different locations within that main tag.
Actually By.linkText() locates <a> elements by the exact text it displays while desire text is not inside any <a> tag. That's why you're in trouble.
You should try using By.xpath() with this text as below :-
WebElement el = driver.findElement(By.xpath(".//div[descendant::td[text() = 'RFI Overview']]"));
System.out.println("Table One Column contains following:\n" + el.getText());
el.click();
Or
WebElement el = driver.findElement(By.xpath(".//div[normalize-space(.) = 'RFI Overview']"));
System.out.println("Table One Column contains following:\n" + el.getText());
el.click();
Or As I'm seeing in provided screenshot desire <div> has id attribute which value looks like unique. If this attribute value is fixed for this element, you can also try using By.id() as :-
WebElement el = driver.findElement(By.id("isc_3BL"));
System.out.println("Table One Column contains following:\n" + el.getText());
el.click();
driver.findElement(By.xpath("//td[.='RFI Overview']")).click();
I'd suggest using the div with id isc_3BL as well, but I am not certain that is a static id. If it is, you could definitely use it to isolate from any other outside table containing the same exact td with text "RFI Overview"
I am working with apose words java recently.
In my first page I have a table need to merge, which can grow any size, no fixed number of rows and at the end of my first page, I want to keep some content (for example contact details) to be fixed. (Note: I can't keep contact details in Footer or in foot note section because of some formatting I need to ensure which can't maintain in footer or foot note section)
On growing of table as many rows, My content is going down, But I want to fix it at the end of my first page. if table grows bigger in size, wanted to skip the content and render table in next page.
is there any solution/work around for this?
My expected results are like below....
Page 1 Start
dynamic Table row1
dynamic Table row2
dynamic Table row3
Contact Details ,wanted to fix at the end of my first page
Page 1 end
Page 2 Start
dynamic table row 4
dynamic table row 5
........
For your scenario, ideally the contact details should be set in a footer. It is possible, but very risky.
First create a new document, either in Aspose.Words or MS Word, it will be used as a template.
Add a blank table on top
Add contact details, after the blank table
Add a bookmark, after the contact details
Now, using Aspose.Words, you can check the location of the bookmark, every time you are adding a new row in the table. If bookmark is at page 1, add new row to the first table. If bookmark is at page 2, add new row to the second table. Below is the sample code that adds rows to the table, keeping the contact details fixed on page 1.
Template document: Google drive link
Java source code is given below.
public static void main(String[] args)
{
try
{
String template = Common.DATA_DIR + "Contact Template.docx";
String saveDocument = Common.DATA_DIR + "Contact with tables.docx";
String bookmarkNameContact = "ContactEnd";
// Load the template
com.aspose.words.Document wordDoc = new com.aspose.words.Document(template);
DocumentBuilder builder = new DocumentBuilder(wordDoc);
// Find the contacts bookmark
com.aspose.words.Bookmark bookmarkContact = wordDoc.getRange().getBookmarks().get(bookmarkNameContact);
// Set the table with null
com.aspose.words.Table table = null;
// Add some rows
for (int i = 0; i < 50; i++)
{
// If contacts bookmark is on 1st page, add new rows to first table
if (getBookmarkPage(wordDoc, bookmarkContact) == 1)
{
table = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 0, true);
} else
{
// If the contacts bookmark is on second page, add rows to second table
table = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 1, true);
// If there is no second table, create it
if (table == null)
{
table = createNewTable(wordDoc, bookmarkContact);
}
}
// Add rows dynamically to either first or second table
addRow(wordDoc, table, "some text " + i);
}
// Save the document
wordDoc.save(saveDocument);
} catch (Exception ex)
{
System.err.println(ex.getMessage());
}
}
private static com.aspose.words.Table createNewTable(com.aspose.words.Document wordDoc, com.aspose.words.Bookmark bookmarkContact) throws Exception
{
// Get the first table and clone it to create the second one
com.aspose.words.Table firstTable = (com.aspose.words.Table) wordDoc.getChild(NodeType.TABLE, 0, true);
com.aspose.words.Table table = (com.aspose.words.Table) firstTable.deepClone(true);
// Add the second table after the bookmark
bookmarkContact.getBookmarkEnd().getParentNode().getParentNode().appendChild(table);
// Delete all its rows
table.getRows().clear();
return table;
}
// Add a new row to the table
private static void addRow(com.aspose.words.Document wordDoc, com.aspose.words.Table table, String text)
{
// Create a new row
com.aspose.words.Row row = new com.aspose.words.Row(wordDoc);
row.getRowFormat().setAllowBreakAcrossPages(true);
// Add it to the table
table.appendChild(row);
// Add cells to the row
for (int iCell = 0; iCell < 4; iCell++)
{
// Create a new cell and set text inside it
com.aspose.words.Cell cell = new com.aspose.words.Cell(wordDoc);
cell.appendChild(new com.aspose.words.Paragraph(wordDoc));
cell.getFirstParagraph().appendChild(new Run(wordDoc, text));
cell.getFirstParagraph().getParagraphFormat().setSpaceAfter(0);
row.appendChild(cell);
}
}
private static int getBookmarkPage(com.aspose.words.Document wordDoc, com.aspose.words.Bookmark bookmarkContact) throws Exception
{
// Find the page number, where our contacts bookmark is
LayoutCollector collector = new LayoutCollector(wordDoc);
return collector.getStartPageIndex(bookmarkContact.getBookmarkEnd());
}
I work with Aspose as Developer Evangelist.
My project has one dynamic table. I need to go to a particular cell and click on an available link. I had reached a particular cell but am unable to click on the link which appears in the table cell.
#Test(priority = 1)
public void projectDelete() throws Exception {
int rowCount = -1;
int columnCount = 0;
WebElement table = webdriver.findElement(By.id("projectList"));
List<WebElement> allRows = table.findElements(By.tagName("tr"));
for (WebElement row : allRows) {
rowCount++;
List<WebElement> rowCells = row.findElements(By.tagName("td"));
for (WebElement cell : rowCells) {
columnCount++;
String projectName = cell.getText();
if (projectName.equals("TEST1")) {
System.out.println("Table Data" + cell.getText());
System.out.println("Table Row " + rowCount);
System.out.println("TEST PROJECT LINE FOUND ..... "
+ rowCount);
webdriver.findElement(By.xpath("//*[#id='projectList']/tbody/tr[rowCount]/td[5]")).click();
webdriver.findElement(By.xpath("//*[#id='493']")).click();
}
}
columnCount = 0;
}
}
Output:
Table DataTEST1
Table Row 76
TEST PROJECT LINE FOUND ..... 76
FAILED: projectDelete
org.openqa.selenium.NoSuchElementException: Unable to locate element: {"method":"xpath","selector":"//*[#id='projectList']/tbody/tr[rowCount]/td[5]"}
Command duration or timeout: 20.06 seconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
On a single pass through your code, I found the following issue
Change the following
webdriver.findElement(By.xpath("//*[#id='projectList']/tbody/tr[rowCount]/td[5]")).click();
to
webdriver.findElement(By.xpath("//*[#id='projectList']/tbody/tr["+rowCount+"]/td[5]")).click();
On second thoughts, I have some suggestions on your code :-
Instead of finding the table as a whole, you can find the tbody since your data under test lies here.
I believe, you know in which column the project name. So you can avoid the loop for iterating through the List rowCells. Instead you can directly use rowCells.get(index) to get the exact column(index starts from 0. If your project name is in column 2, then index =1).
The same is applicable for the column which contains the link to click(). Use rowCell.get(index) to get the column and then click on it.
So your code can be modified as follows :-
#Test(priority = 1)
public void projectDelete() throws Exception {
//find tbody
WebElement table = webdriver.findElement(By.xpath("/table[#id='projectList']/tbody"));
//get all rows
List<WebElement> allRows = table.findElements(By.tagName("tr"));
//iterate through the rows
for (WebElement row : allRows) {
//get the rowCells in each row
List<WebElement> rowCells = row.findElements(By.tagName("td"));
//get the column which contains the project name and get text
String projectName = rowCells.get(indexofColumnwhichhasProjectname).getText();
//Compare if the project name equals TEST1
if (projectName.equals("TEST1")) {
System.out.println("Table Data : " + projectName);
System.out.println("Table Row : " + rowCells.indexOf(projectName));
//get the column containing the link and click on it.
rowCells.get(4).click();
//webdriver.findElement(By.id("493")).click();
//Img is contained within the row containing the project Name
//So, find the Img in the row and click
row.findElements(By.cssSelector("img[alt='Delete Project']")).click(); }
}
}
Let me know if this helps you.