TESTEROPS

A pragmatic approach to QA and OPS

Playwright Table Handling – 2

This is the second post in the series of handling table with Playwright. In the first, I worked on a simple table and then worked on simple scenarios that like getting the data from table, and searching something and then operating on the search results.

In this series, I’ll take another table and will try to do some more complex operations – I’ll also try one or two scenarios for the GRID elements.

So in this we’ll try to see if we can automate the scenarios –

  • Collect multiple selected rows from a table.
  • Get the attribute values from all rows in a table
  • Try to handle a complex scenario for the grid layout.

Collect multiple selected rows from a table

For this example, I’m going to select a different table from the earlier one – https://demo.guru99.com/test/web-table-element.php#

As you can see from this table, the data is dynamic and changes after each refresh – so we cannot use locators using static values.

Now let’s say we want to get only selected values from this table – we only want the Company name, the Prev closing price and the current price. Now how can we do that.

So now, as you can see, that the table has an class datatable, which we can use – to get the table data. Now since we only want the selected rows, we’ll use only those selected childs under the table row <tr> elements.

First we get all the <tr> elements from the table.

Next, we’ll iterate over in each rows, and then get the respective locators for each row element.

td:nth-child(1) for company name.

td:nth-child(3) for prev closing amount.

td:nth-child(4) for current closing amount.

And we’ll use the allInnerTexts() method to get the text contents.

and then push this to an array of objects. Now run the code and see

for(let i=0; i<rowCount; i++){
            let row = tableRows.nth(i);
            let companyName = await row.locator('td:nth-child(1)').allInnerTexts();
            let prevClose = await row.locator('td:nth-child(3)').allInnerTexts();
            let currentPrice = await row.locator('td:nth-child(4)').allInnerTexts();
            
            if(companyName && prevClose && currentPrice){
                data.push({
                    companyName: companyName,
                    prevClose: prevClose,
                    currentPrice: currentPrice
                });
            }
        }

which will print the data to the console.

Get an attribute value from all the rows

In the above case, we selected the data from only selected columns for all rows. Now let’s say instead of text, we want to get the attribute data.

For this example, we’ll use another url – https://www.leafground.com/table.xhtml

Go to this table, and you’ll see some data already populated . Now if you see at the last, there is Activity row, which shows the values in different way.

This activity row contains the data in a progress bar. Let’s see the HTML rendered for this

<div class="ui-progressbar-value ui-widget-header ui-corner-all" style="display:block;width:63%"></div>

As you can see the progress bar data is shown by the style attribute.So how we can get the data for the progressbar and how the data can be printed to the console.

 // selecting all the elements
        const elements = page.locator('div.ui-progressbar-value.ui-widget-header.ui-corner-all');

        // get the count of elements
        const elementsCount = await elements.count();

        for (let i = 0; i < elementsCount; i++) {
            // get style attribute for each element
            const styleAttribute = await elements.nth(i).getAttribute('style');

            // check if style attribute is not null
            if (styleAttribute !== null) {
                // split the styles into an array
                const styles = styleAttribute.split(';');

                // find the width style
                const widthStyle = styles.find(style => style.trim().startsWith('width'));

                // check if width style is found
                if (widthStyle !== undefined) {
                    // get the width value
                    const widthValue = widthStyle.split(':')[1].trim();
                    console.log(`Width value for element ${i + 1}: ${widthValue}`);
                } else {
                    console.log(`Width style not found for element ${i + 1}`);
                }
            } else {
                console.log(`Style attribute not found for element ${i + 1}`);
            }
        }

This prints

Handle a complex scenario for the grid layout.

Now up until now, I’ve tried to automate some really tricky situations on a single table- how about a table inside of a table.

There is a GRID layout where there is a table, and under each table row there is another table -this is available on this link -> https://www.leafground.com/grid.xhtml

Now we want to go to each row of the table, click on the link and then get the inner table and then fetch the details.

If you see the table structure, then you’ll find that the outer table <tr> has a class ui-datatable-selectable that we can use to get the table row data.

And once we have that, we’ll have to iterate over the element with role gridcell and then click on the 1st child.

const tr = await page.locator('tbody.ui-datatable-data.ui-widget-content > tr.ui-datatable-selectable').all()
        const outData = []
        for (let i of tr) {
            const currentRow = i.getByRole('gridcell').nth(2)
            const currentName = await currentRow.innerText()
            await i.getByRole('gridcell').nth(1).click()
            await page.waitForTimeout(2000)
        }

Now to get the text from the inner table, we’ll create a locator that uses a mix of css and xpaths to get to the table , and then use the <tr> element to get the row and then use the allInnerTexts() to get the text.

You can see that there are \t elements in the printed console output. This is something that I’ll be updating in some time after removing them.

All the code that has been used for demonstrating the scenarios are now pushed to github on my github repo – https://github.com/zac11/playwright-table-handling

I hope this series helps someone who is trying to handle HTML data tables in Playwright. The code snippets will make them look easy but in the real time, it might not be easy based on the table’s strucuture.