Skip to main content

How to Work with HTML Data Tables

Intro​

Odds are at some point you've come across the use of tables in a web application to display data or information to a user, giving them the option to sort and manipulate it. Depending on your application it can be quite common and something you will want to write an automated test for.

When the table has no helpful, semantic markup (e.g. easy to use id or class attributes) it quickly becomes more difficult to work with and write tests against it. And if you're able to pull something together, it will likely not work against older browsers.

A Solution​

You can easily traverse a table through the use of CSS Pseudo-classes. But keep in mind that they rely on the position of the elements, so they break when the table layout changes. When you can, get a front-end developer to update the table with helpful attributes.

A quick primer on Tables and CSS Pseudo-classes​

Understanding the broad strokes of an HTML table's structure goes a long way in writing effective automation against it. So here's a quick primer. A table has:- a header (e.g. <thead>)- a body (e.g. <tbody>).- rows (e.g. <tr>) -- horizontal slats of data- columns -- vertical slats of data Columns are made up of cells, which are:- a header (e.g., <th>)- one or more standard cells (e.g., <td> -- which is short for table data)CSS Pseudo-classes work by walking through the structure of an object and targeting a specific part of it based ona relative number (e.g. the third <td> cell from a row in the table body). This works well with tables sincewe can grab all instances of a target (e.g. the third <td> cell from each <tr> in the table body) and use it in our test -- which would give us all of the data for the third column.

Let's step through some examples for a common set of table functionality like sorting columns in ascending and descending order.

Example​

NOTE: You can see the application under test here. It's an example from the-internet. In the example there are 2 tables with the same data.

Here is the markup from the first table. Note that, other than the table itself, its cells don't have any id or class attributes.

<table id="table1" class="tablesorter">
<thead>
<tr>
<th><span>Last Name</span></th>
<th><span>First Name</span></th>
<th><span>Email</span></th>
<th><span>Due</span></th>
<th><span>Web Site</span></th>
<th><span>Action</span></th>
</tr>
</thead>
<tbody>
<tr>
<td>Smith</td>
<td>John</td>
<td>jsmith@gmail.com</td>
<td>$50.00</td>
<td>http://www.jsmith.com</td>
<td>
<a href="#edit">edit</a>
<a href="#delete">delete</a>
</td>
</tr>
...

There are 6 columns. Each one is sortable by clicking on the column header. The first click will sort them in ascending order, the second click in descending order. There is a small sampling of data in the table to work with (4 rows worth), so we can sort the data, grab it, and confirm that it sorted correctly.

Our first test sorts the Due column. We find and click the column heading with a CSS Pseudo-class (#table1 thead tr th:nth-of-type(4)), which targets the 4th <th> element in the table heading. Then we use another pseudo-class to find all the cells of the column (#table1 tbody tr td:nth-of-type(4)), grab their text, clean it up (removing the $), and convert it to a number. Finally, we compare the values to a sorted version of themselves. If they match, the column was sorted in ascending order.

To test for descending order we click the heading twice and compare the values to a sorted and reversed version of themselves. And to test a column that doesn't deal with numbers (e.g., Email) we don't need to clean up or convert the text.

These locators depend on the order of the columns. If a column is added or moved, they break. The second table on the page shows what the markup looks like with some helpful class attributes added in:

<table id="table2" class="tablesorter">
<thead>
<tr>
<th><span class="last-name">Last Name</span></th>
<th><span class="first-name">First Name</span></th>
<th><span class="email">Email</span></th>
<th><span class="dues">Due</span></th>
<th><span class="web-site">Web Site</span></th>
<th><span class="action">Action</span></th>
</tr>
</thead>
<tbody>
<tr>
<td class="last-name">Smith</td>
<td class="first-name">John</td>
<td class="email">jsmith@gmail.com</td>
<td class="dues">$50.00</td>
<td class="web-site">http://www.jsmith.com</td>
...

With these selectors our last test (#table2 thead .dues and #table2 tbody .dues) becomes simpler, more expressive, and more resilient to changes in the table layout, since it doesn't use hard-coded numbers that rely on the column order. If the table you are testing doesn't have them, it's worth asking your front-end developers to add them.

Expected Behavior​

For each test:

  • Open the browser
  • Load the page
  • Click the column heading (once for ascending order, twice for descending order)
  • Grab the values for that column
  • Assert that the column is sorted in the correct order
  • Close the browser

Summary​

CSS Pseudo-classes are a great resource and unlock a lot of potential for your tests. But when you can, prefer semantic locators that don't depend on the layout of the page.

For more info on CSS Pseudo-classes see the MDN reference, and maybe the W3C spec if you're feeling adventurous.

Happy Testing!

Authors​

Dave Piacente
Original creator of Elemental Selenium
Diego Molina
Elemental Selenium maintainer