Playwright stories: Visual comparisons with Dynamic data

Kostiantyn Teltov
5 min readJul 9, 2023
This image was generated by AI https://hotpot.ai/art-generator

Welcome, web enthusiasts! Are you ready to up your web testing game? In this article we are going to walkthrough Playwright feature of screenshot comparison. Sometimes we want to make sure that visually page has not been changed. But our pages may have dynamic data that makes some difficulty. Starting from Playwright/test version “1.35” you can do it very easily. Let’s not waste time and go into details.

Pre-requistion

I assume you are already familiar with Playwright. So this article is not about how to set it up from scratch. This section is to remind you that you should upgrade Playwright/test to the minimum version “1.35”.

You can verify your installed version with the following command

npx @playwright/test — version

You can install specific version with the following command

npm install @playwright/test@1.35

Or you can simple install the latest version(recommend) with the following comand.

npm install @playwright/test@latest

Package.json was also updated:

Hope this step was successful

Visual comparison with non-dynamic data

For testing purposes, I’m going to use my old website: https://qa-automation-test-site.web.app/.

Use case:

  1. Login to website (credentials available in field tooltips)
  2. Navigate to the Input page: https://qa-automation-test-site.web.app/input
  3. Enter constant name to “First name” field
  4. Use Visual Screenshot comparison

Implementation:

I will use beforeEach hook and implement repetitive login and navigation steps

test.beforeEach(async ({ page, baseURL, HomePage}) => {

await new AuthenticationSteps(page).openBasePageAndLoginWithSessionStorage(baseURL as string);

await HomePage.header.clickNavigationMenuButton(HeaderMenuNames.input_fields);});

Now we can go to test implementation logic

  • First we will save variable with constant name:

const firstName = ‘Kostiantyn’;

  • Now we can fill the fild with this value

await InputFieldsPage.fillTextToInputField(InputPageInputFields.FirstName, firstName);

Finally we can implement screenshot comparison assertion

await expect(page).toHaveScreenshot();

You may be wondering where it takes the screenshot? The answer is NOWHERE. It does not exist right now. So, the first run of the test will fail, but will produce a new screenshot

Let’s run the UI mode. You can read more details about this mode in one of my previous articles.

Let’s select and run the test

The test failed, but a new screenshot was created in a new folder in your test catalog.

Now we can run our test again and it will pass, comparing a page with the previously generated screenshot.

Simple? Yes, it is. Unfortunately, our pages can contain dynamic data. So it will not always work like this. Let’s move on to the feature of the day.

Visual comparison with dynamic data

As mentioned earlier, we need to solve a problem with dynamic data. So far we can do this by playing with pixels.

await expect(page).toHaveScreenshot({maxDiffPixels: 10});

Now the Playwright team has designed another cool feature. Let’s extend our use case.

Use case:

  1. Login to website (credentials available in field tooltips)
  2. Navigate to the Input page: https://qa-automation-test-site.web.app/input
  3. Enter dynamic text. Each new run test will add a new value
  4. Use Visual Screenshot comparison with a mask property

Code:

First, we should implement a function to generate random text.

I just created a “string-generator.ts” file in Helpers and exported a declarative function.

Now we can try to implement a test.

  • First, let’s use our function and save value to constant field

const firstName: string = generateRandomString(10);

  • Next, we do the same as previous test. Just filling this input field value.

await InputFieldsPage.fillTextToInputField(InputPageInputFields.FirstName, firstName);

  • And the final magical step is in using a mask with a locator of dynamic element

await expect(page).toHaveScreenshot({

mask: [ page.locator(‘#firstName’) ],

maskColor: ‘red’

});

  • “Mask” property takes array of the Locators. So, you may want to include more then one dynamic field
  • In my example, you may also see “maskColor” property. This is an optional, but it will visualize masked fields during test run.

Important: Please delete the previously created screenshot. It contains old screenshot data. So your test will always fail

  • Now, we can run the test and it will fail again. And will create a screenshot with dynamic data
  • If you you look at the screenshot you will see it highlights dynamic field we are planning to exlcude from comparison.
  • So, everything you need to do is to run the test again and it will be passed.

Here is code example with two fields:

await expect(page).toHaveScreenshot({

mask: [ page.locator(‘#firstName’), page.locator(‘#lastName’) ],

maskColor: ‘red’});

End words

That’s all for today. Frankly, I have always been skeptical about visual testing. But Playwright makes me think it might be a good idea. And it’s very easy to implement. You can find a code example on GitHub: https://github.com/dneprokos/playwright-test-demo/blob/main/_project-test-automation-site-tests/tests/input-page-tests.ts

Good luck and May Force will be with you!

--

--

Kostiantyn Teltov

From Ukraine with NLAW. QA Tech Lead/SDET/QA Architect (C#, JS/TS, Java). Like to build testing processes and help people learn. Dream about making indie games