Visual Regression Testing with AskUI and Jest

Visual Regression Testing with AskUI and Jest
Johannes Dienst
February 13, 2024
Share
linkedin iconmail icon

Visual Regression Testing (VRT) is a useful method to guard yourself against unwanted layout and visual changes that can occur with new version of a Graphical User Interface (GUI).

AskUI is not a testing tool in the original sense but an automation tool for all GUIs that is platform-independent. Wouldn't it be nice to combine VRT with AskUI, so you do not have to maintain two different projects.

Luckily you can do this because Jest - AskUIs favourite runner - can be extended to provide VRT, while AskUI delivers the screenshots to test on.

In this blog you will learn how to use AskUI in combination with Jest and the package jest-image-snapshot to include a visual regression test in your AskUI runs.

Prerequisites

Setup jest-image-snapshot

First you need to install the package that provides the VRT capabilities: jest-image-snapshot.

Installation

Install it as a dev dependency:

-- CODE language-ts line-numbers -- npm install --save-dev jest-image-snapshot

Integration

The package provides a function toMatchImageSnapshot which implements Jest's Matchers<R> interface making it a Jest matcher that can be used with Jest's expect().

We have to add this matcher to Jest with expect.extend like this in your workflow file (See the docs):

-- CODE language-ts line-numbers -- const { toMatchImageSnapshot } = require('jest-image-snapshot'); expect.extend({ toMatchImageSnapshot });

Now the only thing you have to provide for a regression test in your workflows is an image to the function expect() as Buffer:

-- CODE language-ts line-numbers -- expect(imageBuffer).toMatchImageSnapshot();

You can use AskUI to get the screenshot as a base64 encoded string. The string is in the format of a data URL. So you have to strip the scheme data:[<mediatype>][;base64], away because it is not a valid image with the scheme. Here is the full code:

-- CODE language-ts line-numbers -- const annotate = await aui.annotate(); const imageBase64 = annotate.image; // Strip away this: data:image/png;base64, // Not valid png -> Only if used as a data URL let imageBuffer = Buffer.from( imageBase64.split('base64,')[1], 'base64'); expect(imageBuffer).toMatchImageSnapshot();

How to Get it to work with TypeScript

When you run this you will get an error:


 ● Test suite failed to run
 test/my-first-askui-test-suite.test.ts:16:25 - error TS2551: Property 'toMatchImageSnapshot' does not exist on type 'JestMatchers<Buffer>'. Did you mean 'toMatchSnapshot'?
 16     expect(imageBuffer).toMatchImageSnapshot();
                           ~~~~~~~~~~~~~~~~~~~~
   node_modules/@types/jest/index.d.ts:1111:9
   1111         toMatchSnapshot<U extends { [P in keyof T]: any }>(propertyMatchers: Partial<U>, snapshotName?: string): R;
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     'toMatchSnapshot' is declared here.
FAIL  test/my-first-askui-test-suite.test.ts

This is because Jest's typings in jest.d.ts do not include toMatchImageSnapshot.

Luckily TypeScript has a mechanism called Declaration Merging. When we create a file jest.d.ts in our project and declare our matcher there, TypeScript will pick it up.

-- CODE language-ts line-numbers -- declare namespace jest { interface Matchers { toMatchImageSnapshot(): CustomMatcherResult; } }

When you rerun it you will get no error 🥳.

How jest-image-snapshot Works

From the repository:

Given an image (Buffer instance with PNG image data) the toMatchImageSnapshot() matcher will create a image_snapshots directory in the directory the test is in and will store the baseline snapshot image there on the first run. Note that if customSnapshotsDir option is given then it will store baseline snapshot there instead.
On subsequent test runs the matcher will compare the image being passed against the stored snapshot.
To update the stored image snapshot run Jest with --updateSnapshot or -u argument. All this works the same way as Jest snapshots.

You also want to check out the options you can provide to toMatchImageSnapshot() to fine-tune the behaviour. For example you might want to set a threshold for a mismatch so that minimal differences do not fail a run:

-- CODE language-ts line-numbers -- expect(image).toMatchImageSnapshot({ failureThreshold: 0.01, failureThresholdType: 'percent' });

Conclusion

You can use AskUI in combination with a Visual Regression Testing library that integrates with Jest like jest-image-snapshot.

With this you can validate your GUI's final state and ensure it is the one you expected 🥳.

Get in touch

For media queries, drop us a message at info@askui.com