TestCafeとpixelmatchでスナップショットテストをやってみた

## はじめに
ソースコードのリファクタリングなどで、画面表示に変更がないソースコードの改修を行った時に、表示崩れがないことを目視で確認するのが大変ですよね。思わぬところで、表示のズレがあったり・・・
そこで今回は、TestCafeで自動的に画面のスナップショットを撮って、pixelmatchで差分比較まで行う方法をご紹介します。

## 今回使用するツール
### TestCafe
E2E(エンドツーエンド)のWebテストを自動化するNode.jsツール
JavaScriptまたは、TypeScriptでテストコードが作成できます。

https://devexpress.github.io/testcafe/

### pixelmatch
テストでスクリーンショットを比較するために作成された、画像比較用のNode.jsツール

https://github.com/mapbox/pixelmatch

## 今回の流れ
- TestCafeでスナップショットを撮影
- 撮影したスナップショットをpixelmatchで画像比較

試しに、以下の画像を表示したページで動かしてみたいと思います。

##### testA.html
![screenshot1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852338/44514dba-a86a-bdbb-cb45-ca100e2a1df7.png)

##### testB.html
![Screenshot2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852338/fdb6c89f-6062-6f7b-a0d4-d6acf3b6faa2.png)



目視では違いが分かりづらいですが、marginにて画像の表示位置を少しずらしています。

```html:testA.html
<div style="margin: 30px;">
 <img width="200" height="200" src="https://raw.githubusercontent.com/toranoana/special/master/maid-engineers/1_Introduction.png"/>
</div>
```

```html:testB.html
<div style="margin: 35px;">
 <img width="200" height="200" src="https://raw.githubusercontent.com/toranoana/special/master/maid-engineers/1_Introduction.png"/>
</div>
```


## 前提条件
Node Package Manager （以下、npm）が使用できる環境を前提とします。

## TestCafeでスナップショットを撮る
### TestCafeのインストール
npm にて TestCafe をインストールします。

```
$ npm install testcafe
```

インストール確認

```
$ testcafe -v
1.11.0
```

### スナップショットを撮るコード

``` JavaScript:testcafe.js
fixture("Screenshot1").page("https://*****/*****/test/1");

test("Get Screenshot For Screenshot1", async (t) => {
  await t.takeScreenshot({
    path: "screenshot1.png",
    fullPage: true,
  });
});

fixture("Screenshot2").page("https://*****/*****/test/2");

test("Get Screenshot For Screenshot2", async (t) => {
  await t.takeScreenshot({
    path: "Screenshot2.png",
    fullPage: true,
  });
});


```

実行コマンド (※ 今回は、Chromeのヘッドレス環境にて実行します)

```
$ testcafe "chrome:headless" testcafe.js
```
すると、直下に「screenshots」のフォルダーが生成され、そこにスナップショットの画像が生成されます。
![スクリーンショット 2021-03-17 22.30.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852338/20a2a4cb-fa41-67f5-89c9-dc45de466e23.png)
このスナップショットの画像を使って、次はpixelmatchで、画像比較をやってみます。
## pixelmatchで画像を比較する
### pixelmatchのインストール
こちらもnpmを使ってインストールします。

```
$ npm install pixelmatch
```
### スナップショットの差分を出力するコード
``` JavaScript:pixelmatch.js
const fs = require("fs");
const PNG = require("pngjs").PNG;
const pixelmatch = require("pixelmatch");

const img1 = PNG.sync.read(fs.readFileSync("./screenshots/screenshot1.png"));
const img2 = PNG.sync.read(fs.readFileSync("./screenshots/screenshot2.png"));
const { width, height } = img1;
const diff = new PNG({ width, height });

pixelmatch(img1.data, img2.data, diff.data, width, height, { threshold: 0.1 });

fs.writeFileSync("diff.png", PNG.sync.write(diff));
```
実行コマンド 

```
$ node pixelmatch.js
```
すると、同じフォルダー内に「diff.png」が生成されます。これが比較結果の画像になります。
実際に見てみると、表示のズレが発生していることが分かります。
![diff.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/852338/1e64ead4-6510-d219-3a7c-d2daea6459d4.png)

## まとめ
TestCafeでスナップショットの撮影と、pixelmatchで画像比較まで、簡単なソースコードで行うことが出来ました。またTestCafeを使用すると、WebDriverのインストールが必要なく、ブラウザの操作が出来るので凄く便利です。これで少しでも、テストにかかる時間を減らしていきたいです。