Verifying Sortable Tables Using Playwright
Foundations
Frameworks
HTML tables are a common way to display data on a website.
While showing a list of ingredients isn’t necessarily the most critical thing, imagine if this was something like health data or something that scientists actually needed to work properly.
Not only do we want to make sure that this data is displaying appropriately, we want to make sure that when we’re using the sorting features, that it’s also working as expected.
Code-Based Table Testing with Playwright is Tedious
Now, if we’re doing this with traditional code-based tests, we need to make sure that we’re verifying that the integrity of our data isn’t compromised.
That could mean making sure we’re going through each row and column to make sure that each cell has exactly the value that it needs. But also, after that sorting action, we want to ensure that all the data is still working as expected.
Now, this is a lot to maintain, especially when our data could be constantly changing. I don’t want to actually have to maintain fixtures of all that table data.
Using Applitools Eyes SDK for Playwright to Verify Tables
Instead, we’re going to use visual testing, so that when we first load this page, we can make sure that our table looks exactly right. And even after we sort it, that we’re still showing the data exactly how we expect it. In particular, we’re going to use Applitools.
With the Eyes SDK for Playwright, we can easily add visual tests to our existing test with a simple npm package. To start, I can use npm to install Applitools as a dependency.
Once it’s done, I’m going to head over to my code editor, where I can start to import my dependencies, including Eyes and Target, which we’ll use in the test.
To start, I don’t actually need to run all this manual code to check my data beforehand. Instead, I’m going to create a new constant called const eyes, which I’m going to set as a new instance of the Eyes SDK.
Then I want to open up my eyes, similar to like we would a camera lens or even our own personal eyes, where I’m going to first run await eyes.open(). First, I want to pass in the page argument so that we can make sure that we’re running it with Playwright.
I’ll pass in page as my first argument. Then we can set an appName, which in my instance, I’m going to call it “Table” to match the rest of this test. And then I’m going to set a testName where in this instance, let’s call it “Ascending”, since we want to make sure that our table is sorting ascending.
Now is where our actual test comes in where we want to run our visual test by using the check API. We’re going to say await eyes.check(). For the first argument, we can set a Tag. I’m going to say, “Before Sort”.
We also want to tell eyes the part of the page that we want to actually test and, in particular, the Target that we want to test. I’m going to pass in Target where I’m going to first call the method of window saying that I want to check the window of the current viewport. And I’m going to also pass in fully to make sure it captures the entire thing.
Now, the great thing is we don’t actually have to change anything with our actual interaction. We wanted to still try to sort the columns. We don’t need to add anything else for our click.
But just like the “before” data, we don’t want to have to actually run this code-based validation. We’re going to add another check with eyes just like before and let’s call this, “After Sort”.
Finally, when we’re done with our camera, we want to make sure that our lens is actually closed. So, we’ll run await eyes.close.
Before we actually run this test, we want to make sure that we’re associating this test with our Applitools account. We want to export our API key as an environment variable. We’re going to run the command export APPLITOOLS_API_KEY=<your_key>. And we’re going to set that equal to our API key that we can find right inside our Applitools dashboard.
Then just like our other Playwright tests, we can run npm test. We can see that Playwright is going to start up and even open the browser.
Once the test is complete, we can head over to the Applitools dashboard where we can find our test. We can see not only that we have our “Before Sort”, but we can also navigate over and see what happens after we sort it. That way, we can make sure that when our data is sorted, all the other associated columns are lined up appropriately.
Summing It Up – Using Visual Testing with to Verify Tables in Playwright
In review, if we want to make sure that all of our table data is working and sorting just as we expect it to, we don’t want to have to manually test every single cell.
We can use the Applitools Eyes SDK for Playwright where we can make sure that with our eyes, we can both check that it’s working before the sort and after the sort so that we can be confident that we’re displaying our data exactly right.
const { test, expect } = require('@playwright/test');
const { Eyes, Target } = require('@applitools/eyes-playwright')
test.describe('Table', () => {
test.beforeEach(async ({ page }) => {
await page.goto('https://kitchen.applitools.com/ingredients/table');
});
test.describe('with Visual Testing', () => {
test('should verify table data is sorted ascending', async ({ page }) => {
const eyes = new Eyes();
await eyes.open(page, 'Table', 'Ascending');
await eyes.check('Before Sort', Target.window().fully());
await page.click('#column-button-name');
await eyes.check('Ater Sort', Target.window().fully());
await eyes.close();
});
});
test.describe('with manual commands', () => {
const tableDataUnsorted = [
['Apple', 'Fruit', 'Sweet'],
['Lemon', 'Fruit', 'Bitter'],
['Onion', 'Vegetable', 'Bitter'],
['Pepper', 'Vegetable', 'Sweet'],
['Carrots', 'Vegetable', 'Sweet'],
['Banana', 'Fruit', 'Sweet']
]
const tableDataSortedAsc = [
['Apple', 'Fruit', 'Sweet'],
['Banana', 'Fruit', 'Sweet'],
['Carrots', 'Vegetable', 'Sweet'],
['Lemon', 'Fruit', 'Bitter'],
['Onion', 'Vegetable', 'Bitter'],
['Pepper', 'Vegetable', 'Sweet']
]
test('should manually verify table data is sorted ascending', async ({ page }) => {
const dataBefore = await page.$$eval('#fruits-vegetables tbody tr', (rows) => {
return rows.map(row => {
const cells = row.querySelectorAll('td');
return Array.from(cells).map(cell => cell.textContent);
})
});
dataBefore.forEach((row, rowIndex) => {
row.forEach((cell, cellIndex) => {
expect(cell).toContain(tableDataUnsorted[rowIndex][cellIndex]);
});
});
await page.click('#column-button-name');
const dataAfter = await page.$$eval('#fruits-vegetables tbody tr', (rows) => {
return rows.map(row => {
const cells = row.querySelectorAll('td');
return Array.from(cells).map(cell => cell.textContent);
})
});
dataAfter.forEach((row, rowIndex) => {
row.forEach((cell, cellIndex) => {
expect(cell).toContain(tableDataSortedAsc[rowIndex][cellIndex]);
});
});
});
});
});