DEV Community

Cover image for Visual Regression Testing with AskUI and Jest
Johannes Dienst for AskUI

Posted on • Updated on • Originally published at askui.com

Visual Regression Testing with AskUI and Jest

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:

npm install --save-dev jest-image-snapshot
Enter fullscreen mode Exit fullscreen mode

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):

const { toMatchImageSnapshot } = require('jest-image-snapshot');
expect.extend({ toMatchImageSnapshot });
Enter fullscreen mode Exit fullscreen mode

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

expect(imageBuffer).toMatchImageSnapshot();
Enter fullscreen mode Exit fullscreen mode

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:

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();
Enter fullscreen mode Exit fullscreen mode

How to Get it to work with TypeScript

When you run this you will get an error:

FAIL  test/my-first-askui-test-suite.test.ts
  ● 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.
Enter fullscreen mode Exit fullscreen mode

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.

declare namespace jest {
    interface Matchers<R> {
      toMatchImageSnapshot(): CustomMatcherResult;
    }
}
Enter fullscreen mode Exit fullscreen mode

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 the 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:

expect(image).toMatchImageSnapshot({
    failureThreshold: 0.01,
    failureThresholdType: 'percent'
  });
Enter fullscreen mode Exit fullscreen mode

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 🥳.

Top comments (0)