📷

jest-puppeteerとjest-image-snapshotを使ってVisual Regression Testingを試してみる

2022/03/07に公開

はじめに

以下の記事でJestでe2eテストと画像比較テストを実装出来たので、今回はそれらを応用してVisual Regression Testingを実現してみたいと思います。
開発言語は引き続きTypeScriptになります。

https://zenn.dev/kakkoyakakko/articles/d464882b074757

https://zenn.dev/kakkoyakakko/articles/87c1ad4b663afb

対象読者

  • Jestの実装経験がある方
  • e2eテストに興味がある方
  • Visual Regression Testingに興味のある方

Visual Regression Testingとは

  • 日本語では画像回帰テストと訳せます。
  • 画像の差分を検出するスナップショットテストです。
  • HTMLのスナップショットテストとは違い実際の画像を比較するためデザイン崩れなどをチェックすることが出来ます。

作業方針

以下の記事に対して、jest-image-snapshotを導入する形で進めます。

https://zenn.dev/kakkoyakakko/articles/d464882b074757

動作環境

  • Node.js - 14.x
  • Yarn - 1.22.x
  • Jest - 27.5.x
  • ts-jest - 27.1.x
  • TypeScript - 4.5.x
  • jest-puppeteer - 6.1.x
  • jest-image-snapshot - 4.5.x
  • @types/jest - 27.4.x
  • @types/puppeteer - 5.4.x
  • @types/jest-image-snapshot - 4.3.x
  • lite-server - 2.6.x (テスト用WEBサイトとして使用)

サンプルコード

テスト用WEBサイトを構築

テスト環境の設定

test/jest-setup.ts
import { toMatchImageSnapshot } from 'jest-image-snapshot';

// jest-image-snapshotをJestのexpectで使用出来るようにする
expect.extend({ toMatchImageSnapshot });
jest.config.js
module.exports = {
  preset: 'jest-puppeteer',
  moduleFileExtensions: ['js', 'ts'],
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
  testMatch: ['<rootDir>/test/**/*.+(ts|js)'],
  // jestのsetupファイルとしてjest-setup.tsを追加
  setupFilesAfterEnv: ['./test/jest-setup.ts'],
  // jest-setup.tsをテスト対象から除外
  modulePathIgnorePatterns: ['jest-setup.ts'],
};

テストコード実装

test/sample.test.ts
describe('Sample test', () => {
  beforeEach(async () => {
    await page.goto('http://localhost:8000');
  });

  it('screenshot', async () => {
    // ページのスクリーンショットを保存
    const image = await page.screenshot();
    // スクリーンショットと画像スナップショットを比較
    expect(image).toMatchImageSnapshot();
  });

  it('type test', async () => {
    const inputText = 'hoge';
    await page.type('#txt', inputText);
    const actual = await page.$eval('input[id="txt"]', (el) => (el as HTMLInputElement).value);
    expect(actual).toBe(inputText);
    
    // ページのスクリーンショットを保存
    const image = await page.screenshot();
    // スクリーンショットと画像スナップショットを比較
    expect(image).toMatchImageSnapshot();
  });
});
  • puppeteerのスクリーンショット保存機能で画像データを作成して、jest-image-snapshotの画像スナップショットとの比較機能で差分チェックを行います。

動作確認

初回テスト実行時

  • テストが成功してスナップショットが出力されたとログ出力されます。

  • test/__image_snapshots__ディレクトリに画像スナップショットファイルが生成されます。

2回目以降画像差分がある場合

テストコードの修正

以下のコードに修正します。

test/sample.test.ts
describe('Sample test', () => {
  ...省略

  it('type test', async () => {
    // hoge -> hogeeee
    const inputText = 'hogeeee';
    await page.type('#txt', inputText);
    const actual = await page.$eval('input[id="txt"]', (el) => (el as HTMLInputElement).value);
    expect(actual).toBe(inputText);
    
    // ページのスクリーンショットを保存
    const image = await page.screenshot();
    // スクリーンショットと画像スナップショットを比較
    expect(image).toMatchImageSnapshot();
  });
});

テスト実行

  • toMatchImageSnapshotの箇所でテストが失敗します。

  • test/__image_snapshots__/__diff_output__/ディレクトリに画像の比較結果ファイルが出力されます。

画像比較結果ファイル

  • スナップショット画像、DIFF画像、テスト実行時の画像の順で並んだ画像ファイルが出力されます。

ソースコード一式

https://github.com/yasu-s/jest-puppeteer-sample/tree/image-snapshot

おわりに

  • jest-puppeteerとjest-image-snapshotを使用することで簡単にVisual Regression Testingが実現出来ました。
  • リリースのたびに画面崩れが頻発するサイトの場合、まずはjest-puppeteerとjest-image-snapshotを使ってデグレチェックをしてみてはいかがでしょうか。

参考URL

https://jestjs.io/ja/docs/puppeteer
https://www.npmjs.com/package/jest-puppeteer
https://www.npmjs.com/package/jest-image-snapshot

Discussion