From 786953fc0cfa6d265f088e4d3bd0b5babc0bf13f Mon Sep 17 00:00:00 2001 From: May Mei Date: Sat, 17 Oct 2026 10:49:28 +1100 Subject: [PATCH 01/10] docs(recipe): add read-table-rows page skeleton --- docs-site/docs/recipes/read-table-rows.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docs-site/docs/recipes/read-table-rows.md diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md new file mode 100644 index 0000000..42a9725 --- /dev/null +++ b/docs-site/docs/recipes/read-table-rows.md @@ -0,0 +1,16 @@ +--- +description: "TODO (Lisr-iiil): SEO description, under 160 characters" +id: read-table-rows +title: Read table rows +sidebar_label: Read table rows +--- + +# Read table rows + +Read an HTML table as data instead of walking its cells by hand. Call `rows()` on a +locator that points at the ``, and you get back one map per row, keyed by +column header: + + + + \ No newline at end of file From 3a2ac500246c06940bcae5ee3e1f8e58e22f4dea Mon Sep 17 00:00:00 2001 From: May Mei Date: Sat, 17 Oct 2026 11:31:27 +1100 Subject: [PATCH 02/10] docs(recipe): add example table and read-all-rows snippet --- docs-site/docs/recipes/read-table-rows.md | 25 ++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 42a9725..982e353 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -9,8 +9,27 @@ sidebar_label: Read table rows Read an HTML table as data instead of walking its cells by hand. Call `rows()` on a locator that points at the `
`, and you get back one map per row, keyed by -column header: +column header. - +{/* Part 1 (May): snippets: read rows, find a row by column value, assert on a cell */} - \ No newline at end of file +Example table with three columns (Last Name, First Name, and Due) and two rows: +```html +
+ + + + + + + +
Last NameFirst NameDue
SmithJohn$50.00
DoeJason$100.00
+``` + +```java +List> rows = $("#table1").rows(); +// [{Last Name=Smith, First Name=John, Due=$50.00}, +// {Last Name=Doe, First Name=Jason, Due=$100.00}] +``` + +{/* Part 2 (Lisr-iiil): short rows and -only group rows */} \ No newline at end of file From 41286ecd60aaba42b8738653934265f2ef1fa20f Mon Sep 17 00:00:00 2001 From: May Mei Date: Sat, 17 Oct 2026 11:45:47 +1100 Subject: [PATCH 03/10] docs(recipe): add find-row-by-column-value snippet --- docs-site/docs/recipes/read-table-rows.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 982e353..168a59e 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -32,4 +32,14 @@ List> rows = $("#table1").rows(); // {Last Name=Doe, First Name=Jason, Due=$100.00}] ``` +`rows()` returns a plain `List`, so finding a row by a column's value is ordinary Java: + +```java +Map doe = rows.stream() + .filter(row -> row.get("Last Name").equals("Doe")) + .findFirst() + .orElseThrow(); +// {Last Name=Doe, First Name=Jason, Due=$100.00} +``` + {/* Part 2 (Lisr-iiil): short rows and -only group rows */} \ No newline at end of file From d8ae2fc72d4778c4ba5632163c4c8ab33cac0c2b Mon Sep 17 00:00:00 2001 From: May Mei Date: Sat, 17 Oct 2026 12:02:48 +1100 Subject: [PATCH 04/10] docs(recipe): add assert-on-a-cell snippet --- docs-site/docs/recipes/read-table-rows.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 168a59e..cd66d3e 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -9,7 +9,7 @@ sidebar_label: Read table rows Read an HTML table as data instead of walking its cells by hand. Call `rows()` on a locator that points at the ``, and you get back one map per row, keyed by -column header. +column header. {/* Part 1 (May): snippets: read rows, find a row by column value, assert on a cell */} @@ -26,7 +26,7 @@ Example table with three columns (Last Name, First Name, and Due) and two rows:
``` -```java +```java List> rows = $("#table1").rows(); // [{Last Name=Smith, First Name=John, Due=$50.00}, // {Last Name=Doe, First Name=Jason, Due=$100.00}] @@ -42,4 +42,14 @@ Map doe = rows.stream() // {Last Name=Doe, First Name=Jason, Due=$100.00} ``` +Then assert on a cell by its column header: + +```java +import org.testng.Assert; + +// Check Jason Doe's due amount +Assert.assertEquals(doe.get("Due"), "$100.00"); +// fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 +``` + {/* Part 2 (Lisr-iiil): short rows and -only group rows */} \ No newline at end of file From a3796c6e53bc822ea2c0b501797ab202c676690a Mon Sep 17 00:00:00 2001 From: u8167278 Date: Sat, 17 Oct 2026 22:50:48 +0800 Subject: [PATCH 05/10] docs(recipe): explain short table rows --- docs-site/docs/recipes/read-table-rows.md | 26 ++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index cd66d3e..ba32fb8 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -52,4 +52,28 @@ Assert.assertEquals(doe.get("Due"), "$100.00"); // fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 ``` -{/* Part 2 (Lisr-iiil): short rows and -only group rows */} \ No newline at end of file +{/* Part 2 (Lisr-iiil): short rows and -only group rows */} + +## Short rows + +When a data row has fewer `` cells than there are headers, `rows()` still +includes every header key. Missing trailing cells have the value `""`, not `null`. +For example, replace the table's `` with: + +```html + + SmithJohn + DoeJason$100.00 + +``` + +```java +List> rows = $("#table1").rows(); +Map smith = rows.get(0); +Assert.assertTrue(smith.containsKey("Due")); +Assert.assertEquals(smith.get("Due"), ""); +``` + +Cells are matched to headers by position. Omitting a middle `` shifts the +remaining values to earlier columns; use an empty `` to preserve that +column's position. Cells beyond the number of headers are ignored. From c189b17da96e45a1b5d4e4d8aabba5c2ce001146 Mon Sep 17 00:00:00 2001 From: u8167278 Date: Sun, 18 Oct 2026 10:08:04 +0800 Subject: [PATCH 06/10] docs(recipe): explain th-only group rows --- docs-site/docs/recipes/read-table-rows.md | 52 ++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index ba32fb8..18cdb42 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -54,11 +54,19 @@ Assert.assertEquals(doe.get("Due"), "$100.00"); {/* Part 2 (Lisr-iiil): short rows and -only group rows */} +The examples below use variations of the same `#table1` table. Keep its `` +and three column headers unchanged, and replace only the `` as shown in +each section. Read the rows again after loading each variation; each Java block +is a separate example rather than additional statements in the same method. + ## Short rows When a data row has fewer `` cells than there are headers, `rows()` still includes every header key. Missing trailing cells have the value `""`, not `null`. -For example, replace the table's `` with: + +In the HTML below, Smith's final `` has been removed from the original example, +while Doe's row is unchanged. Replace only the original table's `` with +this fragment; keep `` and its ``: ```html @@ -67,9 +75,15 @@ For example, replace the table's `` with: ``` +After loading the modified table, use the same `$("#table1").rows()` call as in +the core example. Select Smith's row and assert both that the `Due` key exists +and that its value is an empty string. This distinguishes a missing cell value +from a missing map key: + ```java List> rows = $("#table1").rows(); Map smith = rows.get(0); +// {Last Name=Smith, First Name=John, Due=} Assert.assertTrue(smith.containsKey("Due")); Assert.assertEquals(smith.get("Due"), ""); ``` @@ -77,3 +91,39 @@ Assert.assertEquals(smith.get("Due"), ""); Cells are matched to headers by position. Omitting a middle `` to preserve that column's position. Cells beyond the number of headers are ignored. + +## Group rows containing only `
` shifts the remaining values to earlier columns; use an empty `` + +After the table header has been selected, rows with no `` cells are skipped. +A ``-only group heading does not become a data row or change the header keys: + +Starting with the short-row variation above, add a group heading before Smith's +row. Its single `` spans all three columns, and it has no `` cells. +Keep the original `` and `` again, replacing only +the `` with: + +```html + + + + + +``` + +Load this table variation and read it with the same `rows()` call. Assert that +the result contains only the two data rows, in order, and that their names are +still available under the original `Last Name` header. The group heading must +not appear as an extra data row: + +```java +List> rows = $("#table1").rows(); +// [{Last Name=Smith, First Name=John, Due=}, +// {Last Name=Doe, First Name=Jason, Due=$100.00}] +Assert.assertEquals(rows.size(), 2); +Assert.assertEquals(rows.get(0).get("Last Name"), "Smith"); +Assert.assertEquals(rows.get(1).get("Last Name"), "Doe"); +``` + +Keep the column headers in `` as shown above. Without a `` header, +the first row containing `
Outstanding accounts
SmithJohn
DoeJason$100.00
` cells supplies the keys, so a group heading +before the column headers would be interpreted as the header instead. From 387db2fc0e55cbfe907abbf85c3747e4a642796b Mon Sep 17 00:00:00 2001 From: u8167278 Date: Sun, 18 Oct 2026 12:03:59 +0800 Subject: [PATCH 07/10] docs(recipe): remove placeholders and complete final verification Remove the completed Part 1 and Part 2 placeholder comments. Final verification: - Browser: 6 tests passed in a separate local TestNG project using real Chrome and HTML fixtures, covering recipe scenarios and an expected assertion failure. - Framework: mvn clean verify -Dgpg.skip=true passed with 710 tests. - Documentation: built the docs site successfully and checked the recipe locally for text and code block rendering. --- docs-site/docs/recipes/read-table-rows.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 18cdb42..2a4bb4d 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -11,8 +11,6 @@ Read an HTML table as data instead of walking its cells by hand. Call `rows()` o locator that points at the ``, and you get back one map per row, keyed by column header. -{/* Part 1 (May): snippets: read rows, find a row by column value, assert on a cell */} - Example table with three columns (Last Name, First Name, and Due) and two rows: ```html
@@ -52,8 +50,6 @@ Assert.assertEquals(doe.get("Due"), "$100.00"); // fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 ``` -{/* Part 2 (Lisr-iiil): short rows and ` and three column headers unchanged, and replace only the `` as shown in each section. Read the rows again after loading each variation; each Java block From bef22303962ede54cfb741f2709c414484adb231 Mon Sep 17 00:00:00 2001 From: u8167278 Date: Sun, 18 Oct 2026 18:29:37 +0800 Subject: [PATCH 08/10] docs(recipe): add sidebar entry and SEO description Add the recipe to the Recipes sidebar and provide a 138-character SEO description. Add a core-usage heading and clarify example results. Final validation: - Contribution checks: framework verification passed with 710 tests; official consumer verification passed with 111 tests and 2 expected skips. - Recipe and documentation checks: all 8 local TestNG tests passed in real Chrome; docs build, page rendering, and sidebar navigation checked. --- docs-site/docs/recipes/read-table-rows.md | 6 +++++- docs-site/sidebars.js | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 2a4bb4d..c28993e 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -1,5 +1,5 @@ --- -description: "TODO (Lisr-iiil): SEO description, under 160 characters" +description: "Read HTML table rows with Selenium Boot Locator.rows(), find rows by column value, assert cells, and handle short rows and group headings." id: read-table-rows title: Read table rows sidebar_label: Read table rows @@ -11,6 +11,8 @@ Read an HTML table as data instead of walking its cells by hand. Call `rows()` o locator that points at the `
-only group rows */} - The examples below use variations of the same `#table1` table. Keep its `
`, and you get back one map per row, keyed by column header. +## Read, find, and assert on rows + Example table with three columns (Last Name, First Name, and Due) and two rows: ```html
@@ -82,6 +84,7 @@ Map smith = rows.get(0); // {Last Name=Smith, First Name=John, Due=} Assert.assertTrue(smith.containsKey("Due")); Assert.assertEquals(smith.get("Due"), ""); +// Both assertions pass: the Due key is retained and its missing cell is mapped to "". ``` Cells are matched to headers by position. Omitting a middle `` as shown above. Without a `` header, diff --git a/docs-site/sidebars.js b/docs-site/sidebars.js index bc790c3..a8450a7 100644 --- a/docs-site/sidebars.js +++ b/docs-site/sidebars.js @@ -65,6 +65,7 @@ const sidebars = { 'recipes/handle-new-windows', 'recipes/drag-and-drop', 'recipes/handle-shadow-dom', + 'recipes/read-table-rows', ], }, { From 6aeb74af820571b90edf00152ce9889363b9ca99 Mon Sep 17 00:00:00 2001 From: DONGQI LI Date: Mon, 19 Oct 2026 17:35:44 +0800 Subject: [PATCH 09/10] docs(recipe): simplify table row edge-case explanations --- docs-site/docs/recipes/read-table-rows.md | 54 +++++++---------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index c28993e..22d89a5 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -52,19 +52,13 @@ Assert.assertEquals(doe.get("Due"), "$100.00"); // fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 ``` -The examples below use variations of the same `#table1` table. Keep its `` -and three column headers unchanged, and replace only the `` as shown in -each section. Read the rows again after loading each variation; each Java block -is a separate example rather than additional statements in the same method. +For each example below, reuse `#table1` and its ``, replacing only the ``. ## Short rows -When a data row has fewer `` with -this fragment; keep `
` shifts the @@ -118,6 +121,7 @@ List> rows = $("#table1").rows(); Assert.assertEquals(rows.size(), 2); Assert.assertEquals(rows.get(0).get("Last Name"), "Smith"); Assert.assertEquals(rows.get(1).get("Last Name"), "Doe"); +// All three assertions pass: the group heading is skipped, leaving Smith and Doe in order. ``` Keep the column headers in `
` cells than there are headers, `rows()` still -includes every header key. Missing trailing cells have the value `""`, not `null`. - -In the HTML below, Smith's final `` has been removed from the original example, -while Doe's row is unchanged. Replace only the original table's `
` and its ``: +When a row has fewer ` @@ -73,33 +67,24 @@ this fragment; keep `
` cells than there are headers, `rows()` retains every +header key and fills missing trailing values with `""`. Here, Smith's final +cell is missing, while Doe's row is complete: ```html
` and its ``: ``` -After loading the modified table, use the same `$("#table1").rows()` call as in -the core example. Select Smith's row and assert both that the `Due` key exists -and that its value is an empty string. This distinguishes a missing cell value -from a missing map key: - ```java List> rows = $("#table1").rows(); Map smith = rows.get(0); -// {Last Name=Smith, First Name=John, Due=} Assert.assertTrue(smith.containsKey("Due")); Assert.assertEquals(smith.get("Due"), ""); -// Both assertions pass: the Due key is retained and its missing cell is mapped to "". +// Smith retains the Due key with an empty-string value. +Assert.assertEquals(rows.get(1).get("Due"), "$100.00"); +// Doe's complete row keeps its original value. ``` -Cells are matched to headers by position. Omitting a middle `` to preserve that -column's position. Cells beyond the number of headers are ignored. +Note that cells are matched by position. Omitting a middle `` to preserve the position. +Cells beyond the header count are ignored. ## Group rows containing only ``, replacing only the ``. ## Short rows @@ -105,3 +116,5 @@ Assert.assertEquals(rows.get(1).get("Last Name"), "Doe"); Note that header selection matters: without a `` header, the first row containing `` so a preceding group heading is not selected as the header. + +**Deeper reference:** [Accessibility-First Locators](/docs/guides/semantic-locators) — the `$()` / `Locator` API that `rows()` belongs to.
` shifts the -remaining values to earlier columns; use an empty `` shifts later +values to earlier columns; use an empty `` -After the table header has been selected, rows with no `` cells are skipped. -A ``-only group heading does not become a data row or change the header keys: - -Starting with the short-row variation above, add a group heading before Smith's -row. Its single `` spans all three columns, and it has no `` cells. -Keep the original `` and `` again, replacing only -the `` with: +Once the column headers are selected, rows containing no ` @@ -109,21 +94,14 @@ the `` with: ``` -Load this table variation and read it with the same `rows()` call. Assert that -the result contains only the two data rows, in order, and that their names are -still available under the original `Last Name` header. The group heading must -not appear as an extra data row: - ```java List> rows = $("#table1").rows(); -// [{Last Name=Smith, First Name=John, Due=}, -// {Last Name=Doe, First Name=Jason, Due=$100.00}] Assert.assertEquals(rows.size(), 2); Assert.assertEquals(rows.get(0).get("Last Name"), "Smith"); Assert.assertEquals(rows.get(1).get("Last Name"), "Doe"); -// All three assertions pass: the group heading is skipped, leaving Smith and Doe in order. +// The group heading is skipped; Smith and Doe remain in order. ``` -Keep the column headers in `` as shown above. Without a `` header, -the first row containing `` header, the first row +containing `` so a +preceding group heading is not selected as the header. From 127f69380481e35e6b3c7d8ad78324c30f72c140 Mon Sep 17 00:00:00 2001 From: May Mei Date: Tue, 20 Oct 2026 08:32:14 +1100 Subject: [PATCH 10/10] docs(recipe): restructure main example as a test class and add deeper reference --- docs-site/docs/recipes/read-table-rows.md | 59 ++++++++++++++--------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/docs-site/docs/recipes/read-table-rows.md b/docs-site/docs/recipes/read-table-rows.md index 22d89a5..5362a20 100644 --- a/docs-site/docs/recipes/read-table-rows.md +++ b/docs-site/docs/recipes/read-table-rows.md @@ -13,7 +13,8 @@ column header. ## Read, find, and assert on rows -Example table with three columns (Last Name, First Name, and Due) and two rows: +Given a table like this: + ```html
` cells are +skipped. The group heading below spans three columns but is not a data row: ```html
` cells supplies the keys, so a group heading -before the column headers would be interpreted as the header instead. +Note that header selection matters: without a `
` supplies the keys. Keep the column headers in `
@@ -26,32 +27,42 @@ Example table with three columns (Last Name, First Name, and Due) and two rows:
``` -```java -List> rows = $("#table1").rows(); -// [{Last Name=Smith, First Name=John, Due=$50.00}, -// {Last Name=Doe, First Name=Jason, Due=$100.00}] -``` +read it, find a row by a column's value, and assert on a cell: -`rows()` returns a plain `List`, so finding a row by a column's value is ordinary Java: - -```java -Map doe = rows.stream() - .filter(row -> row.get("Last Name").equals("Doe")) - .findFirst() - .orElseThrow(); -// {Last Name=Doe, First Name=Jason, Due=$100.00} -``` - -Then assert on a cell by its column header: - -```java +```java title="AccountsTableTest.java" +import com.seleniumboot.test.BaseTest; +import java.util.List; +import java.util.Map; import org.testng.Assert; - -// Check Jason Doe's due amount -Assert.assertEquals(doe.get("Due"), "$100.00"); -// fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 +import org.testng.annotations.Test; + +public class AccountsTableTest extends BaseTest { + + @Test + public void doeOwesOneHundred() { + open("/accounts"); + + // One map per row, keyed by column header: + // [{Last Name=Smith, First Name=John, Due=$50.00}, + // {Last Name=Doe, First Name=Jason, Due=$100.00}] + List> rows = $("#table1").rows(); + + // Find a row by a column's value + Map doe = rows.stream() + .filter(row -> row.get("Last Name").equals("Doe")) + .findFirst() + .orElseThrow(); + + // Assert on a cell by its column header + Assert.assertEquals(doe.get("Due"), "$100.00"); + // fails with: expected [$100.00] but found [$90.00] if the cell says $90.00 + } +} ``` +`rows()` returns a plain `List`, so finding a row is ordinary Java: a stream as above, +or a `for` loop if you prefer. + For each example below, reuse `#table1` and its `
` supplies the keys. Keep the column headers in `