Web Tables in Selenium WebDriver
Web Tables are one of the most common components found in modern web applications. They are used to display structured information such as employee records, customer details, product lists, order information, transaction history, student records, reports, and dashboard data. In Selenium WebDriver automation, testers frequently need to read table data, validate rows and columns, identify a particular record, click buttons inside a row, select checkboxes, edit or delete records, and handle tables that change dynamically.
Selenium WebDriver provides powerful methods such as findElement() and findElements() that can be combined with XPath, CSS selectors, WebElement methods, loops, conditions, and explicit waits to automate web tables effectively.
Selenium Training Resources: Selenium Training Course | Register for Course Demo
1. What is a Web Table?
A Web Table is an HTML element used to represent structured data in rows and columns. A typical HTML table consists of a table container, rows, headers, and individual data cells.
For example, an employee table may contain Employee ID, Name, Department, Salary, Status, and Actions columns.
2. Why Web Tables are Important in Selenium
Web tables are important because many business applications display critical information in tabular form. Automation scripts may need to verify that the displayed information is correct and interact with a particular record.
- Read table data.
- Validate table headers.
- Count rows and columns.
- Find a particular record.
- Click buttons inside a row.
- Select checkboxes inside rows.
- Edit a specific record.
- Delete a specific record.
- Validate sorting.
- Handle pagination.
- Validate filtered results.
- Compare UI data with expected data.
3. Basic HTML Structure of a Web Table
A standard HTML table can contain the following elements:
- <table> - Defines the table.
- <thead> - Contains table headers.
- <tbody> - Contains table data.
- <tfoot> - Contains footer information.
- <tr> - Defines a table row.
- <th> - Defines a header cell.
- <td> - Defines a data cell.
4. Example HTML Web Table
<table id="employeeTable">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
<th>Salary</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>101</td>
<td>John</td>
<td>QA</td>
<td>50000</td>
<td><button>Edit</button></td>
</tr>
<tr>
<td>102</td>
<td>David</td>
<td>Development</td>
<td>70000</td>
<td><button>Edit</button></td>
</tr>
</tbody>
</table>
5. Web Table Automation Flow
Open Web Page
|
v
Locate Table
|
v
Locate Rows
|
v
Locate Cells
|
v
Read Table Data
|
+------------------+
| |
v v
Validate Data Perform Action
|
+----------+----------+
| | |
v v v
Edit Delete Checkbox
6. Locating the Complete Table
The first step is usually to locate the table element using an ID, name, CSS selector, XPath, or another suitable locator.
WebElement table = driver.findElement(By.id("employeeTable"));
Using XPath:
WebElement table = driver.findElement(
By.xpath("//table[@id='employeeTable']")
);
7. Locating All Rows
The findElements() method can be used to locate multiple rows.
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
System.out.println("Total rows: " + rows.size());
8. Why findElements() is Used for Rows
A table contains multiple rows. Therefore, findElements() is generally more appropriate when we want to retrieve all matching rows.
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
9. Counting Table Rows
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
int rowCount = rows.size();
System.out.println("Number of rows: " + rowCount);
10. Counting Table Columns
List<WebElement> columns = driver.findElements(
By.xpath("//table[@id='employeeTable']//thead/tr/th")
);
System.out.println("Number of columns: " + columns.size());
11. Reading All Table Rows
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
for (WebElement row : rows) {
System.out.println(row.getText());
}
12. Reading All Cells from Every Row
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
for (WebElement row : rows) {
List<WebElement> cells = row.findElements(By.tagName("td"));
for (WebElement cell : cells) {
System.out.print(cell.getText() + " | ");
}
System.out.println();
}
13. Reading Table Headers
List<WebElement> headers = driver.findElements(
By.xpath("//table[@id='employeeTable']//thead/tr/th")
);
for (WebElement header : headers) {
System.out.println(header.getText());
}
14. Getting a Specific Cell
Suppose we want to retrieve the value from the second row and third column.
WebElement cell = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[2]/td[3]")
);
System.out.println(cell.getText());
XPath indexing starts from 1, so tr[2] means the second row and td[3] means the third cell.
15. Getting a Specific Row
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[2]")
);
System.out.println(row.getText());
16. Getting a Specific Column
To retrieve all names from the Name column:
List<WebElement> names = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr/td[2]")
);
for (WebElement name : names) {
System.out.println(name.getText());
}
17. Finding a Row Using Text
This is one of the most useful techniques for dynamic web tables. Instead of depending on a row number, we can identify the row using unique cell text.
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[td[normalize-space()='John']]")
);
System.out.println(row.getText());
18. Understanding the Dynamic XPath
//table[@id='employeeTable']//tbody/tr[
td[normalize-space()='John']
]
This XPath means: locate a row inside the employee table where one of its cells contains the text John.
19. Finding a Cell by Text
WebElement cell = driver.findElement(
By.xpath("//table[@id='employeeTable']//td[normalize-space()='John']")
);
System.out.println(cell.getText());
20. Finding a Row by Employee ID
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[td[normalize-space()='101']]")
);
System.out.println(row.getText());
21. Finding an Action Button Inside a Row
Many tables contain buttons such as Edit, Delete, View, Approve, Reject, or Download. Once the correct row is identified, we can locate the button relative to that row.
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[td[normalize-space()='John']]")
);
WebElement editButton = row.findElement(
By.cssSelector("button.edit")
);
editButton.click();
22. Edit a Record Based on Row Data
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[td[normalize-space()='John']]")
);
row.findElement(By.cssSelector("button.edit")).click();
This approach is much more reliable than clicking a hard-coded row number.
23. Delete a Record Based on Row Data
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[td[normalize-space()='David']]")
);
row.findElement(By.cssSelector("button.delete")).click();
24. Click a View Button Inside an Order Row
WebElement orderRow = driver.findElement(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]")
);
orderRow.findElement(By.cssSelector("button.view")).click();
25. Selecting a Checkbox Inside a Row
WebElement row = driver.findElement(
By.xpath("//table[@id='users']//tbody/tr[td[normalize-space()='John']]")
);
WebElement checkbox = row.findElement(
By.cssSelector("input[type='checkbox']")
);
if (!checkbox.isSelected()) {
checkbox.click();
}
26. Getting the Number of Cells in a Row
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[1]")
);
List<WebElement> cells = row.findElements(By.tagName("td"));
System.out.println("Cells: " + cells.size());
27. Reading a Row Cell by Cell
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[1]")
);
List<WebElement> cells = row.findElements(By.tagName("td"));
for (WebElement cell : cells) {
System.out.println(cell.getText());
}
28. Printing the Complete Table
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
for (WebElement row : rows) {
List<WebElement> cells = row.findElements(By.tagName("td"));
for (WebElement cell : cells) {
System.out.print(cell.getText() + "\t");
}
System.out.println();
}
29. Web Table Using CSS Selectors
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
List<WebElement> cells = driver.findElements(
By.cssSelector("#employeeTable tbody tr td")
);
30. XPath vs CSS for Tables
| Requirement | XPath | CSS |
| Locate table by ID | //table[@id='employeeTable'] | #employeeTable |
| Locate rows | //table[@id='employeeTable']//tbody/tr | #employeeTable tbody tr |
| Locate cells | //table[@id='employeeTable']//tbody/tr/td | #employeeTable tbody tr td |
| Find row by text | Supported directly | Requires different strategy |
| Navigate parent/ancestor | Very powerful | More limited |
31. Static Web Table
A static web table contains a relatively fixed set of rows and columns. The number and structure of rows usually remain stable during the interaction.
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
for (WebElement row : rows) {
System.out.println(row.getText());
}
32. Dynamic Web Table
A dynamic web table can change its content, number of rows, columns, pagination, or records based on API responses, database data, search filters, sorting, user actions, or asynchronous requests.
For dynamic tables, avoid depending only on row indexes. Instead, locate rows using stable attributes or unique business data.
33. Static vs Dynamic Web Tables
| Feature | Static Table | Dynamic Table |
| Rows | Usually predictable | Can change |
| Data | Usually fixed | Often generated dynamically |
| Pagination | May not exist | Common |
| Search | May be simple | Often dynamic |
| Automation | Relatively simple | Requires robust locators and synchronization |
34. Why Hard-Coded Row Numbers Should Be Avoided
Consider the following XPath:
//table[@id='orders']//tbody/tr[3]/td[2]
This may fail when the application sorts the table or when a new record is inserted above the third row.
A better approach is to locate the row using a unique value.
//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]/td[2]
35. Getting Another Cell from the Identified Row
Suppose the order ID is known and we need the customer name from the same row.
WebElement customer = driver.findElement(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]/td[2]")
);
System.out.println(customer.getText());
36. Getting Price from a Product Row
WebElement price = driver.findElement(
By.xpath("//table[@id='products']//tbody/tr[td[normalize-space()='Laptop']]/td[3]")
);
System.out.println(price.getText());
37. Validating a Cell Value
String actualStatus = driver.findElement(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]/td[4]")
).getText();
String expectedStatus = "Delivered";
Assert.assertEquals(actualStatus, expectedStatus);
38. Validating Whether a Row Exists
List<WebElement> matchingRows = driver.findElements(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]")
);
Assert.assertFalse(matchingRows.isEmpty());
39. Validating Table Headers
List<WebElement> headers = driver.findElements(
By.xpath("//table[@id='employeeTable']//thead/tr/th")
);
List<String> actualHeaders = new ArrayList<>();
for (WebElement header : headers) {
actualHeaders.add(header.getText().trim());
}
List<String> expectedHeaders = Arrays.asList(
"ID", "Name", "Department", "Salary", "Action"
);
Assert.assertEquals(actualHeaders, expectedHeaders);
40. Validating Number of Rows
int actualRows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
).size();
Assert.assertEquals(actualRows, 10);
41. Handling an Empty Table
Some applications display a message such as “No records found” when a table contains no data.
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
if (rows.isEmpty()) {
System.out.println("No records found");
} else {
System.out.println("Records available: " + rows.size());
}
42. Handling No Search Results
List<WebElement> rows = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
if (rows.size() == 0) {
WebElement message = driver.findElement(
By.xpath("//*[contains(normalize-space(),'No records found')]")
);
System.out.println(message.getText());
}
43. Dynamic Tables and Explicit Wait
Dynamic tables may require synchronization because table rows can appear after an API call or AJAX request.
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("//table[@id='employeeTable']//tbody/tr")
));
44. Waiting for a Specific Row
WebDriverWait wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
WebElement row = wait.until(
ExpectedConditions.visibilityOfElementLocated(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]")
)
);
45. Waiting for Table Data to Load
By tableRows = By.xpath("//table[@id='orders']//tbody/tr");
wait.until(ExpectedConditions.numberOfElementsToBeMoreThan(
tableRows,
0
));
46. Dynamic AJAX Table
AJAX-based tables may load data without refreshing the entire page. Selenium must wait for the relevant table content instead of using fixed delays.
wait.until(ExpectedConditions.invisibilityOfElementLocated(
By.cssSelector(".table-loader")
));
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("#orders tbody tr")
));
47. Why Thread.sleep() Should Be Avoided
Using Thread.sleep() introduces a fixed delay regardless of whether the table is ready. Explicit waits are generally more flexible because they wait for a specific condition.
Thread.sleep(5000);
Prefer:
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("#orders tbody tr")
));
48. Handling Pagination in Web Tables
Large tables often divide records into multiple pages. Automation must navigate through pages and collect or validate records.
Page 1
|
v
Read rows
|
v
Click Next
|
v
Wait for new rows
|
v
Read rows
|
v
Click Next
|
v
Repeat
|
v
Last Page
49. Identifying the Next Button
WebElement nextButton = driver.findElement(
By.cssSelector(".pagination .next")
);
50. Checking Whether Next Button is Disabled
WebElement nextButton = driver.findElement(
By.cssSelector(".pagination .next")
);
boolean disabled = !nextButton.isEnabled();
System.out.println("Next disabled: " + disabled);
Some applications indicate the disabled state using a CSS class or the disabled attribute. Always inspect the application's actual HTML structure.
51. Looping Through All Pages
while (true) {
List<WebElement> rows = driver.findElements(
By.cssSelector("#orders tbody tr")
);
for (WebElement row : rows) {
System.out.println(row.getText());
}
WebElement nextButton = driver.findElement(
By.cssSelector(".pagination .next")
);
if (!nextButton.isEnabled()) {
break;
}
nextButton.click();
wait.until(ExpectedConditions.stalenessOf(rows.get(0)));
}
52. Important Point About Pagination
When navigating between pages, Selenium should wait for the old page elements to become stale or for the new table content to appear. This helps prevent synchronization problems.
53. Handling StaleElementReferenceException
When a table refreshes, previously stored WebElement objects may no longer refer to the current DOM elements. Selenium can then throw StaleElementReferenceException.
A safer approach is to locate the rows again after the table refresh.
driver.findElement(By.cssSelector(".next")).click();
wait.until(ExpectedConditions.presenceOfElementLocated(
By.cssSelector("#orders tbody tr")
));
List<WebElement> updatedRows = driver.findElements(
By.cssSelector("#orders tbody tr")
);
54. Searching Inside a Table
Many tables have a search field. The test can enter a value and validate the filtered result.
WebElement searchBox = driver.findElement(
By.id("tableSearch")
);
searchBox.clear();
searchBox.sendKeys("John");
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("#employeeTable tbody tr")
));
55. Validating Filtered Results
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
for (WebElement row : rows) {
Assert.assertTrue(
row.getText().toLowerCase().contains("john")
);
}
56. Sorting a Web Table
Tables may provide sortable columns such as Name, Price, Date, Salary, or Status. Selenium can click a header and validate the resulting order.
driver.findElement(
By.xpath("//table[@id='employeeTable']//th[normalize-space()='Name']")
).click();
57. Reading Values Before Sorting
List<WebElement> nameCells = driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr/td[2]")
);
List<String> names = new ArrayList<>();
for (WebElement cell : nameCells) {
names.add(cell.getText().trim());
}
58. Validating Alphabetical Sorting
List<String> actual = new ArrayList<>(names);
List<String> expected = new ArrayList<>(names);
Collections.sort(expected);
Assert.assertEquals(actual, expected);
59. Descending Sort Validation
List<String> expected = new ArrayList<>(names);
expected.sort(Collections.reverseOrder());
Assert.assertEquals(actual, expected);
60. Numeric Table Data Validation
Numbers displayed in tables are often retrieved as strings. Convert them into numeric values before performing mathematical comparisons.
String priceText = cell.getText().replace("$", "").replace(",", "");
double price = Double.parseDouble(priceText);
System.out.println(price);
61. Validating Prices
String priceText = cell.getText()
.replace("$", "")
.replace(",", "")
.trim();
double price = Double.parseDouble(priceText);
Assert.assertTrue(price > 0);
62. Date Validation in Tables
Date columns require careful handling because the displayed format may vary.
String dateText = cell.getText().trim();
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse(dateText, formatter);
System.out.println(date);
63. Status Validation
String status = driver.findElement(
By.xpath("//table[@id='orders']//tbody/tr[td[normalize-space()='ORD1001']]/td[4]")
).getText();
Assert.assertEquals(status, "Delivered");
64. Working with Links Inside Tables
WebElement row = driver.findElement(
By.xpath("//table[@id='users']//tbody/tr[td[normalize-space()='John']]")
);
row.findElement(By.tagName("a")).click();
65. Working with Buttons Inside Tables
WebElement row = driver.findElement(
By.xpath("//table[@id='users']//tbody/tr[td[normalize-space()='John']]")
);
row.findElement(By.tagName("button")).click();
66. Multiple Buttons in the Same Row
If a row contains multiple buttons, use a specific class or attribute rather than simply selecting the first button.
row.findElement(By.cssSelector("button.edit")).click();
67. Multiple Actions Example
row.findElement(By.cssSelector("button.view")).click();
row.findElement(By.cssSelector("button.edit")).click();
row.findElement(By.cssSelector("button.delete")).click();
68. Extracting Table Data into a List
List<List<String>> tableData = new ArrayList<>();
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
for (WebElement row : rows) {
List<String> rowData = new ArrayList<>();
for (WebElement cell : row.findElements(By.tagName("td"))) {
rowData.add(cell.getText().trim());
}
tableData.add(rowData);
}
69. Creating a Reusable Web Table Utility
public List<List<String>> getTableData(
By tableRowsLocator) {
List<List<String>> data = new ArrayList<>();
List<WebElement> rows =
driver.findElements(tableRowsLocator);
for (WebElement row : rows) {
List<String> rowData = new ArrayList<>();
List<WebElement> cells =
row.findElements(By.tagName("td"));
for (WebElement cell : cells) {
rowData.add(cell.getText().trim());
}
data.add(rowData);
}
return data;
}
70. Utility Method to Find a Row
public WebElement findRowByText(
By rowsLocator,
String expectedText) {
List<WebElement> rows =
driver.findElements(rowsLocator);
for (WebElement row : rows) {
if (row.getText().contains(expectedText)) {
return row;
}
}
throw new NoSuchElementException(
"Row not found: " + expectedText
);
}
71. Utility Method to Get Cell Value
public String getCellValue(
By rowLocator,
int columnIndex) {
WebElement row = driver.findElement(rowLocator);
List<WebElement> cells =
row.findElements(By.tagName("td"));
return cells.get(columnIndex - 1)
.getText()
.trim();
}
72. Page Object Model for Web Tables
In a Page Object Model framework, table locators and table operations can be placed inside a page class or reusable component class.
public class EmployeePage {
private WebDriver driver;
private By employeeRows =
By.cssSelector("#employeeTable tbody tr");
public EmployeePage(WebDriver driver) {
this.driver = driver;
}
public List<WebElement> getEmployeeRows() {
return driver.findElements(employeeRows);
}
}
73. Page Object Method to Find Employee
public WebElement getEmployeeRow(String employeeName) {
return driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[
td[normalize-space()='" + employeeName + "']
]")
);
}
For complex applications, it is better to construct dynamic locators carefully and validate input values before using them in XPath.
74. E-Commerce Product Table Example
Imagine an application displaying products with Product Name, Category, Price, Stock, and Action.
| Product | Category | Price | Stock | Action |
| Laptop | Electronics | 75000 | Available | Buy |
| Keyboard | Accessories | 1500 | Available | Buy |
| Monitor | Electronics | 18000 | Out of Stock | View |
75. Finding a Product Row
WebElement productRow = driver.findElement(
By.xpath("//table[@id='products']//tbody/tr[
td[normalize-space()='Laptop']
]")
);
76. Clicking Buy for a Specific Product
productRow.findElement(
By.cssSelector("button.buy")
).click();
77. Checking Product Availability
String stock = productRow.findElement(
By.cssSelector(".stock")
).getText();
Assert.assertEquals(stock, "Available");
78. Employee Table Example
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
for (WebElement row : rows) {
List<WebElement> cells =
row.findElements(By.tagName("td"));
String id = cells.get(0).getText();
String name = cells.get(1).getText();
String department = cells.get(2).getText();
String salary = cells.get(3).getText();
System.out.println(
id + " | " +
name + " | " +
department + " | " +
salary
);
}
79. Order Management Table Example
Order management systems frequently use tables containing Order ID, Customer, Date, Amount, Status, and Actions.
WebElement orderRow = driver.findElement(
By.xpath("//table[@id='orders']//tbody/tr[
td[normalize-space()='ORD1001']
]")
);
String customer = orderRow.findElement(
By.cssSelector(".customer")
).getText();
String status = orderRow.findElement(
By.cssSelector(".status")
).getText();
System.out.println(customer);
System.out.println(status);
80. Handling Nested Tables
Some applications contain a table inside a table cell. In such cases, first locate the parent row or cell and then search inside it.
WebElement parentRow = driver.findElement(
By.cssSelector("#orders tbody tr")
);
WebElement nestedTable = parentRow.findElement(
By.cssSelector("table")
);
List<WebElement> nestedRows =
nestedTable.findElements(By.cssSelector("tbody tr"));
81. Web Table Inside an IFrame
If the table exists inside an iframe, Selenium must switch into that iframe before locating the table.
WebElement frame = driver.findElement(
By.cssSelector("iframe#tableFrame")
);
driver.switchTo().frame(frame);
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
driver.switchTo().defaultContent();
82. Web Table Inside a Modal
WebElement modal = driver.findElement(
By.cssSelector(".modal")
);
List<WebElement> rows = modal.findElements(
By.cssSelector("table tbody tr")
);
83. Handling Hidden Rows
Some tables may contain hidden rows. Selenium can locate elements that exist in the DOM even when they are not currently visible.
List<WebElement> rows = driver.findElements(
By.cssSelector("#employeeTable tbody tr")
);
for (WebElement row : rows) {
if (row.isDisplayed()) {
System.out.println(row.getText());
}
}
84. Handling Row Highlighting
Some tables highlight a row when it is selected. Selenium can click the row and then validate its class or selected state.
WebElement row = driver.findElement(
By.xpath("//table[@id='users']//tbody/tr[td[normalize-space()='John']]")
);
row.click();
String className = row.getAttribute("class");
Assert.assertTrue(
className.contains("selected")
);
85. Complete Web Table TestNG Example
import java.time.Duration;
import java.util.List;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class WebTableTest {
WebDriver driver;
WebDriverWait wait;
@BeforeMethod
public void setup() {
driver = new ChromeDriver();
wait = new WebDriverWait(
driver,
Duration.ofSeconds(10)
);
driver.manage().window().maximize();
}
@Test
public void validateEmployeeTable() {
driver.get("https://example.com/employees");
By rowsLocator =
By.cssSelector("#employeeTable tbody tr");
wait.until(
ExpectedConditions.numberOfElementsToBeMoreThan(
rowsLocator,
0
)
);
List<WebElement> rows =
driver.findElements(rowsLocator);
Assert.assertTrue(rows.size() > 0);
for (WebElement row : rows) {
System.out.println(row.getText());
}
WebElement johnRow = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[
td[normalize-space()='John']
]")
);
Assert.assertTrue(
johnRow.isDisplayed()
);
}
@AfterMethod
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
86. Web Table Test Scenario
- Launch the application.
- Navigate to the employee page.
- Wait for the table to load.
- Verify the table is displayed.
- Verify table headers.
- Count the number of rows.
- Search for an employee.
- Identify the employee row.
- Read employee information.
- Validate the department.
- Validate the salary.
- Click Edit.
- Update employee information.
- Save changes.
- Verify the updated information.
87. Web Table with Checkboxes
List<WebElement> rows = driver.findElements(
By.cssSelector("#users tbody tr")
);
for (WebElement row : rows) {
String userName = row.findElement(
By.cssSelector(".username")
).getText();
if (userName.equals("John")) {
WebElement checkbox = row.findElement(
By.cssSelector("input[type='checkbox']")
);
if (!checkbox.isSelected()) {
checkbox.click();
}
break;
}
}
88. Web Table with Edit and Delete Actions
WebElement row = driver.findElement(
By.xpath("//table[@id='users']//tbody/tr[
td[normalize-space()='John']
]")
);
row.findElement(By.cssSelector("button.edit")).click();
wait.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector("#editUserModal")
));
89. Negative Testing for Web Tables
Web table automation should also verify incorrect, missing, empty, or unexpected data.
- Search for a non-existing record.
- Verify no-result message.
- Validate empty table behavior.
- Validate duplicate records.
- Validate missing values.
- Validate incorrect status.
- Validate invalid numeric values.
- Validate invalid date formats.
- Verify disabled action buttons.
- Verify pagination boundaries.
90. Boundary Testing for Tables
- Zero records.
- One record.
- Maximum records on one page.
- Exactly one full page of data.
- More records than one page.
- Last page containing one record.
- Very large datasets.
91. Duplicate Record Validation
Set<String> employeeNames = new HashSet<>();
for (WebElement row : rows) {
String name = row.findElement(
By.cssSelector("td:nth-child(2)")
).getText().trim();
boolean added = employeeNames.add(name);
Assert.assertTrue(
added,
"Duplicate employee found: " + name
);
}
92. Validating Table Data Against Expected Data
List<String> expectedNames =
Arrays.asList("John", "David", "Robert");
List<String> actualNames = new ArrayList<>();
for (WebElement row : rows) {
actualNames.add(
row.findElement(
By.cssSelector("td:nth-child(2)")
).getText().trim()
);
}
Assert.assertEquals(actualNames, expectedNames);
93. Common Selenium Exceptions with Web Tables
| Exception | Possible Cause | Solution |
| NoSuchElementException | Incorrect locator or row not loaded | Verify locator and use an explicit wait |
| StaleElementReferenceException | Table refreshed | Locate the row again |
| ElementClickInterceptedException | Another element blocks the button | Wait for clickable state or handle overlay |
| TimeoutException | Expected table condition did not occur | Review wait condition and application state |
| IndexOutOfBoundsException | Requested cell does not exist | Check row/column count |
94. Common Mistakes in Web Table Automation
- Using fixed row numbers everywhere.
- Using absolute XPath unnecessarily.
- Not waiting for dynamic data.
- Storing WebElements across table refreshes.
- Ignoring pagination.
- Not handling empty results.
- Assuming every row has the same number of cells.
- Using Thread.sleep() for synchronization.
- Not validating that the correct row was selected.
- Using generic locators when stable attributes are available.
95. Best Practices for Web Tables
- Prefer stable IDs and data attributes when available.
- Use relative XPath for dynamic rows.
- Locate actions relative to the identified row.
- Use explicit waits for dynamic content.
- Do not depend unnecessarily on row indexes.
- Re-locate elements after table refreshes.
- Build reusable table utility methods.
- Keep table logic inside Page Objects or reusable components.
- Validate both positive and negative scenarios.
- Handle pagination systematically.
- Keep locators readable and maintainable.
96. Recommended Locator Strategy
| Priority | Locator | Example |
| 1 | ID | By.id("employeeTable") |
| 2 | Stable data attribute | By.cssSelector("[data-testid='employee-table']") |
| 3 | CSS Selector | By.cssSelector("#employeeTable tbody tr") |
| 4 | Relative XPath | By.xpath("//table[@id='employeeTable']//tbody/tr") |
| 5 | Absolute XPath | Avoid when possible |
97. Web Table Automation Architecture
TestNG Test
|
v
Page Object
|
v
Web Table Utility
|
+---- Locate Table
|
+---- Locate Rows
|
+---- Locate Cells
|
+---- Read Data
|
+---- Find Row
|
+---- Click Action
|
+---- Validate Data
|
v
Application
98. Real-World Use Cases
- Employee management systems.
- Banking transaction tables.
- E-commerce product tables.
- Order management systems.
- CRM customer tables.
- Student management systems.
- Hospital patient records.
- Admin dashboards.
- Financial reports.
- Inventory management systems.
- Flight booking records.
- Payment transaction history.
99. Practical Mini Project
Create an automation test for an Employee Management application.
Requirements
- Open the employee management application.
- Locate the employee table.
- Verify the table headers.
- Count the available records.
- Search for an employee.
- Identify the employee row dynamically.
- Read employee department and salary.
- Validate employee status.
- Click Edit for the selected employee.
- Update the employee information.
- Save the changes.
- Verify the updated row.
- Test pagination.
- Test sorting.
- Test empty search results.
100. Web Table Interview Questions
Q1. What is a Web Table?
A Web Table is an HTML component that displays structured information in rows and columns.
Q2. Which HTML tags are commonly used in a table?
The common tags are <table>, <tr>, <th>, and <td>.
Q3. How do you find all rows of a table?
driver.findElements(
By.xpath("//table[@id='employeeTable']//tbody/tr")
);
Q4. How do you find all cells from a row?
row.findElements(By.tagName("td"));
Q5. How do you find a particular row based on text?
By.xpath("//table[@id='employeeTable']//tbody/tr[
td[normalize-space()='John']
]")
Q6. How do you click an Edit button for a particular row?
WebElement row = driver.findElement(
By.xpath("//table[@id='employeeTable']//tbody/tr[
td[normalize-space()='John']
]")
);
row.findElement(By.cssSelector("button.edit")).click();
Q7. How do you handle dynamic tables?
Use stable locators, identify rows using unique data, apply explicit waits, and re-locate elements after table refreshes.
Q8. How do you handle pagination?
Read the current page, identify whether the Next button is available, click it, wait for the new data, and repeat until the last page.
Q9. Why is findElements() useful for tables?
It returns a collection of matching WebElements, making it useful for processing multiple rows or cells.
Q10. How do you handle StaleElementReferenceException?
Re-locate the table row or cell after the DOM has been refreshed and use appropriate synchronization.
101. Quick Revision
- Use findElement() for one table element.
- Use findElements() for multiple rows or cells.
- Use tr for rows.
- Use td for data cells.
- Use th for headers.
- Use relative XPath to locate dynamic rows.
- Identify rows using unique business data.
- Perform actions relative to the selected row.
- Use explicit waits for dynamic tables.
- Handle pagination carefully.
- Re-locate elements after table refreshes.
- Validate sorting, filtering, and table data.
- Use reusable Web Table utility methods.
102. Web Table Automation Checklist
| Task | Completed |
| Locate the table | ☐ |
| Locate table headers | ☐ |
| Locate table rows | ☐ |
| Count rows | ☐ |
| Count columns | ☐ |
| Read table data | ☐ |
| Find row by unique text | ☐ |
| Click action inside row | ☐ |
| Handle checkboxes | ☐ |
| Handle dynamic data | ☐ |
| Handle pagination | ☐ |
| Handle sorting | ☐ |
| Handle filtering | ☐ |
| Validate table data | ☐ |
| Handle empty results | ☐ |
| Handle stale elements | ☐ |
| Create reusable utility methods | ☐ |
| Implement Page Object Model | ☐ |
| Write TestNG test cases | ☐ |
103. Conclusion
Web Tables are an important part of Selenium WebDriver automation because enterprise applications frequently present business data in tabular form. Effective table automation requires more than simply locating rows and cells. A robust Selenium test should identify records using stable and meaningful information, locate actions relative to the correct row, synchronize with dynamically loaded data, handle pagination, validate sorting and filtering, and gracefully handle empty or changing tables.
By combining XPath, CSS selectors, findElements(), WebElement methods, explicit waits, loops, conditions, TestNG, and Page Object Model, testers can create reliable and maintainable automation for both static and dynamic web tables.
Learn more: Selenium Training Course | Register for Course Demo