6

The Essential Guide to Automated Visual Regression Testing

 3 years ago
source link: https://hackernoon.com/the-essential-guide-to-automated-visual-regression-testing-2l2k3467
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

The Essential Guide to Automated Visual Regression Testing

May 3rd 2021 new story
6
heart.pngheart.pngheart.pngheart.png
light.pnglight.pnglight.pnglight.png
boat.pngboat.pngboat.pngboat.png
money.pngmoney.pngmoney.pngmoney.png

@csouchetSouchet Céline

R&D Engineer at Bonitasoft. Working on an open source project: https://github.com/process-analytics

As developers, it is our job to ensure that our users get an experience with no regression.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Like any good developer, when I add a feature or fix a bug, I also create unit, integration, and end-to-end tests. This assures that, when the existing code is modified, nothing is accidentally broken, and confirms that user flows are functional.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Like many people, I’ve gotten used to using a manual process to visually check that the design looks as intended.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Refactoring, adding a new component, or updating a package can sometimes change the appearance of the application. It can get laborious to click through every possible user journey, and we are not immune to forgetting a test or to miss a small visual change.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

So how can we make sure that the visuals are always correct and less painful to test? I had heard of automatic testing for no visual regression before. I looked into using Selenium some time ago, but changed projects and no longer needed it.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Now that I have a need for visual checks in my current project, I’ve found there are different libraries — easy to learn — that can take screenshots of current web pages and compare generated screenshots with a screenshot baseline to find regressions in the user interface (UI).

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In this article, I will explain how to use one of these libraries — Jest-Image-Snapshot (Jest matcher) — in a Typescript project.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Project example

I will use the BPMN Visualization project (version 0.10.0) as an example. (This example has been simplified so it shows more clearly the configuration and features explained in this article.) The goal of this project is to load BPMN content, and render it.
Automated visual tests will simplify our life with each refactoring, addition of a new component, update of the positioning algorithm of the different BPMN elements, or update of the MxGraph rendering library.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Prerequisites

As a first step, we need to install the required packages as devDependencies:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • Jest + its type definition: A JavaScript Testing Framework
    Jest is a fully featured testing framework, developed by Facebook. It needs very little configuration and works basically out of the box.
npm install -D jest @types/jest
0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • Puppeteer + its type definition: A Node library to control Chrome or Chromium, both in headless mode and with a user interface. It is possible to perform most of the actions that are done manually on a browser and take screenshots.
npm install -D puppeteer @types/puppeteer jest-puppeteer
0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • Jest-Image-Snapshot + its type definition: A Jest matcher to perform image comparisons
npm i -D jest-image-snapshot @types/jest-image-snapshot
0 reactions
heart.png
light.png
money.png
thumbs-down.png

Configuration

Let’s configure the previous libraries.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Configure Jest

I won’t go into detail here on all the different ways to configure Jest. If you already use Jest for your unit/e2e tests, this is not new for you. If you would like more explanations about Jest, there are many great articles available.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In this example, we have 3 Jest configurations: unit tests, e2e tests, and performance tests. We added the visual tests in the e2e test suite. Here I will just explain how we configure Jest for the e2e tests.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

First, create the Jest configuration file (jest.config.js) at ./test/e2e directory:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This configuration sets the root directory to the root project directory, runs .ts files with ts-jest module and looks for .spec.ts and test.ts files under any subdirectory of ./test/e2e directory.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Configure Puppeteer

  • Create a new file (./test/e2e/jest-puppeteer.config.js) for the Puppeteer configuration to run the server & launch the browser once for all tests:

With this configuration, we start a server on the port 10002 with a timeout of 30s, start a browser with a timeout of 2 minutes, and pipe the browser process stdout and stderr into process.stdout and process.stderr.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Extend the Jest expect assertion mechanism to use Jest Image Snapshot

This is the part that might be new, but with a little configuration, we will be ready soon.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

By default, Jest doesn’t know anything about Jest-Image-Snapshot and its assertion toMatchImageSnapshot. So we’ll need to extend Jest. For that, create a new file (./test/e2e/jest.image.ts), like the following:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

To avoid extending Jest in each test file or import the previous file globally in all test files, we need to configure Jest to run it immediately after the test framework has been installed in the environment with setupFilesAfterEnv (Jest property) in ./test/e2e/jest.config.js.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Add a new command

To simply the test execution, add the following script in the ./package.json file:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Now, you can run your e2e tests with the following command:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
npm run test:e2e
0 reactions
heart.png
light.png
money.png
thumbs-down.png

Note: cross-env is useful if you run the tests on different OS.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

You can find the different properties to customize Jest-Image-Snapshot in its README on Github.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Create a basic test with Jest-Image-Snapshot

If everything is configured correctly, we are now ready to create our first visual regression test (./test/e2e/bpmn.rendering.test.ts) by combining Puppeteer and Jest and Jest-Image-Snapshot!

0 reactions
heart.png
light.png
money.png
thumbs-down.png

After the test runs, a new directory will be created — __image_snapshots__ — with an image for each toMatchImageSnapshot call. The names of the snapshots are computed by default with testPath, currentTestName, counter and defaultIdentifier.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Example of generated snapshot:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

bpmn-rendering-test-ts-no-bpmn-gateway-visual-regression-1-snap.png

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Note: Make sure that the snapshot files are committed in your source control so they are shared with other developers and CI environments.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Test on different machines

One issue with one-to-one pixel matching is that there is a good chance that the test will be in error on a machine other than on which it was developed, because every environment has slightly different ways of rendering the same application.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For example, suppose that we want to run the tests on the CI environment every time we create a pull request to the master branch in GitHub. Without any modifications to the code, the test is passed locally; but on the CI environment, it fails with a message like this:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Error: Expected image to match or be a close match to snapshot but was 0.0005804554357724534% different from snapshot (2.7861860917077763 differing pixels).

And a new image file for the diff is stored in the __image_snapshots__/__diff_output__ directory with the name <snapshot_name>-diff.png.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

If we use the previous test, we’ll have something like this:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

bpmn-rendering-test-ts-no-bpmn-gateway-visual-regression-1-diff.png

0 reactions
heart.png
light.png
money.png
thumbs-down.png

You can modify the previous jest-image-snapshot configuration (./test/e2e/bpmn.rendering.test.ts), and update the value of failureThreshold (default value: 0) & failureThresholdType (default value: pixel). These properties are used to calculate the threshold of tolerated differences (before the test fails).

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Warning: If you increase the failure threshold too much, when there is too much difference between local and CI environments, it may be impossible to detect visual regressions.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Order the snapshots

If you have 10 or more tests, it can become complicated to find which screenshot corresponds to which test/feature in the directory __image_snapshots__.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Modify the customSnapshotsDir property to have a different value according to the tests.

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • ./test/e2e/helpers/visu-utils.ts
  • ./test/e2e/bpmn.rendering.test.ts
  • ./test/e2e/bpmn.navigation.test.ts

Reuse the snapshots

Sometimes the expected result/snapshot is the same even after different actions. To avoid having a lot of identical snapshots in the Github repository, it’s better to reuse a snapshot.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

For that, it’s necessary to override the default customSnapshotIdentifier & customDiffDir properties.

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • customSnapshotIdentifier: the custom name to give this snapshot. This preventsthe name of the snapshots from being computed with testPath, currentTestName, counter and defaultIdentifier.
  • customDiffDir: the custom absolute path of a directory to keep this diff in. As we use the same snapshot in different tests, to know which diff file corresponds to which test, we need to set a different value according to the tests.
  • ./test/e2e/helpers/visu-utils.ts
  • ./test/e2e/diagram.rendering.test.ts

Conclusion

With so many operating systems, web browsers, and screen resolutions, Visual Testing can be a powerful tool to assure that an application works well in all possible environments. It is definitely worth trying it as a complement to other sets of tests.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Now you have everything you need to start your first visual regression test in Typescript with Jest & Puppeteer.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Thank you for reading and I hope I helped or inspired you :)

0 reactions
heart.png
light.png
money.png
thumbs-down.png

References

Also published on: https://medium.com/nerd-for-tech/automated-visual-regression-testing-with-typescript-puppeteer-jest-and-jest-image-snapshot-9e14dd9d0fe7

0 reactions
heart.png
light.png
money.png
thumbs-down.png
6
heart.pngheart.pngheart.pngheart.png
light.pnglight.pnglight.pnglight.png
boat.pngboat.pngboat.pngboat.png
money.pngmoney.pngmoney.pngmoney.png
by Souchet Céline @csouchet. R&D Engineer at Bonitasoft. Working on an open source project: https://github.com/process-analyticsRead my stories
Join Hacker Noon

Create your free account to unlock your custom reading experience.


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK