デザイナーでも出来る！Visual Regression Test 導入

# はじめに
[Ateam LifeDesign Advent Calendar 2022](https://qiita.com/advent-calendar/2022/ateam-life-design)、投稿します。
「デザイナーでも出来る」記事シリーズです。

- 私が現在担当している事業サービスでは、`Next.js + React + TypeScript` を用いてフロントエンドの開発を行っています。
- 今回、その`課題解決の手段`として `Visual Regression Test(VRT)` を導入したのですが、その経緯や流れについてご紹介できればと思います。
（そして、名前はカッコいいけど長いので、以下できるだけ VRT と呼びます。）
- よくあるVRT紹介記事 と違う点としては、`Webデザイナー職だけど導入できた` / `事業サービスの課題・導入経緯の詳細アリ` というところです。

:::note info
**この記事の内容について**
今回導入した内容は、**StorybookベースのVRT** になります。
**CI/CDへの組み込み や Docker周りの設定** はエンジニアに協力してもらっています。
:::

:::note warn
**この記事で書かないこと**
**【他のVRT技術 との 比較】**
他のVRT技術（Playwright や Chromaticなど）には触れません。

**【VRT導入後の 担当事業サービス での実際の運用結果】**
最小構成で導入した後、どのように運用しているかには触れません。
:::

**想定する対象者**
- フロントエンドに興味のあるデザイナー
- VRT に興味のあるフロントエンドエンジニア
- Storybookを用いてVRTの導入 を検討されている方


# 担当事業サービス の５つの課題
### ①リリース前後 に 表示崩れ と 500エラー に気付けなかった
**修正リリース後 しばらく日が経ってから、該当URLの特定のコンテンツが表示できず 500エラーの状態 になっていることが発覚し、少額の利益損失に**
- もちろん STG / 本番環境 で表示検証を行なった上でのリリースでしたが、`確認ページ数が多く`、`目視確認(人の目)しか検証方法がなく`、ミスが起こりやすい状況だった。
- この時点では `修正前後のUI表示差分 を 検知する仕組み` を導入できていなかった。
- `500エラーを検知する仕組み` は導入済みだったが、バグでうまく機能していなかった。
  - こちらはバグ修正し、その後しっかり検知されるようになりました。
  - 逆に 大きな利益損失を出してしまう前に気付けたこと は 不幸中の幸い だったかも。

### ②担当事業メンバーの異動
**ちょうど 社内の体制 が変わり始める前のタイミングで、上記のエラーが発生**
- 社内の体制が変わり、`今後は人の異動が前提` となる中で、事業ドメインに詳しいメンバーがいなくても、`誰が入ってもしっかり表示検証を担保できる仕組み`が必要に。
- そして、`最小構成メンバーで事業を回していける土台づくり`が必要。

### ③担当事業サービス の優先度低下
**社内の他サービス の優先度が上がり、担当事業サービス の優先度は下がり、開発はストップの状態に。**
- 開発がストップしたので、リリースが無ければ何も変更がないので問題なさそうだが、
`次回リリース時に不安を大きく抱えたままリリース作業`をすることになってしまう。
- `優先度が低くなった事業だからこそ、事前に不用意なエラーを防ぐ仕組みづくり`をしておきたい。

### ④表示検証の工数増大
**修正によるUI表示 が担保できているか確認する手段 が 目視確認 しかない**
- 結局、開発ストップの判断後でも、表記修正などの細々したリリースは行う必要があり、毎回たっぷり工数をかけて `触ったファイルに紐付く全ページを目視確認で検証` してリリースを進めることに。。
- `表示検証の工数 を 仕組みで効率化して削減`し、`他に集中すべきタスク に 工数をかけられるように`したい。

### ⑤担当事業サービス ではVRTが導入されていない
**社内の他サービス では既に Storybook や VRT が導入されていたのに、担当事業サービス は同じような技術スタックなのに導入されていなかった。**
- え？ じゃあ入れよう、となった。
- 既に `社内の成功事例` や `うまく運用に乗っている設定がある状態`だったので、同様に展開。
  - ただ、`この事業独自の仕様`はあるので、そこは合わせる形で。
- VRT導入による解決やメリット を事業側に伝え、工数を確保して導入を進めることに。
  - この辺り、`実際にエラーによって事業に損失が出ていた`からこそ、仕組みを導入しよう、という流れは早かった。


# 課題解決の手段
- **Visual Regression Test（VRT）**

## Visual Regression Test（VRT） とは？
- 画像回帰テスト のことです。
  - 各単語を翻訳：`Visual（視覚） / Regression（回帰） / Test（テスト）`
- 要するに、`コード変更前後のUIのスナップショットを比較し、崩れがないか差分確認できるテスト`
  - `スナップショット`とは、`ある時点でのUIを保存したもの` のことですね。


## 主に使用したライブラリ

### 1. Storybook
https://storybook.js.org/

**概要 / 用途**
- 今やフロントエンド で デファクトの、UIカタログツール です。
- 各UIコンポーネントに対するStoryファイルを作成し、スナップショットの対象とします。
  - 画像の比較は、このStoryファイルが対象になりますので、VRTの機能だけ を導入しても Storyファイル が用意できていなければVRTできません。
  - また今回、 `VRT導入を目的とする、Storybookの導入`が軸なので、不要な option追加はナシ。

### 2. Storycap
https://github.com/reg-viz/storycap

**概要 / 用途**
- Storybook からスナップショットを生成するためのツールです。
  - reg-suit と[作者が同じ](https://quramy.medium.com/folio%E3%81%AE%E7%94%BB%E5%83%8F%E5%9B%9E%E5%B8%B0%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%A3%8F%E5%81%B4-c848030991bc)です。
  - ブラウザ操作ツール の [Puppeteer](https://github.com/puppeteer/puppeteer) も一緒に追加しないと動かないので入れます。
  - Storyファイルのキャプチャ方法(タイミングやサイズなど)を制御したいので、`Managed mode` で使用します。

### 3. reg-suit
https://github.com/reg-viz/reg-suit

**概要 / 用途**
- 汎用的な VRT の枠組みを提供するツールです。
  - storycap と[作者が同じ](https://quramy.medium.com/folio%E3%81%AE%E7%94%BB%E5%83%8F%E5%9B%9E%E5%B8%B0%E3%83%86%E3%82%B9%E3%83%88%E3%81%AE%E8%A3%8F%E5%81%B4-c848030991bc)です。
  - 比較元、比較先の画像を検証にかけ、差分の有無を検知してくれます。
  - 検証の結果 を分かりやすい形式でレポートしてくれます。


# VRT導入手順
前置きが長くなりましたが、ここから導入手順です。

① Storybook の導入
② Storyファイル の作成
③ storycap の導入
④ reg-suit の導入
⑤ レポートストレージの設置 と CI/CDの設定
⑥ VRT の動作検証


## ① Storybook の導入
**以下コマンドで、Storybook を導入**
```terminal
$ npx storybook init
```

```terminal
~

Field 'browser' doesn't contain a valid alias configration
```
いきなりエラーでコケました。。
- まずは `Storybookを導入する前に、エラー解消` が必要でした。
  - 既存プロダクトに追加する際には、こういうのあるあるな気がします。
  - プロダクトを保守するという意味で、コードを見返す良い機会になりました。
- 以下の点の修正が必要でした。
  - `tsconfig.json` で記述した エイリアスのパス が間違っているコンポーネントがある
  - importするファイルの参照先 が間違っている

エラー修正後、再度コマンドを実行し、無事 Storybook を導入できました。

**main.js と preview.js の調整**
- コマンド実行後、自動で新たにファイル追加されるので、調整します。
- preview.js は、アプリ側と同じ構成 になるようにします。


## ② Storyファイル の作成
- 全UIコンポーネント に対する Storyファイルを作成します。
  - 今回は最小構成で導入のため、1ファイルだけ用意。
  - フォーマットは [CSF3](https://storybook.js.org/blog/component-story-format-3-0/) で作成します。

例）`Header.tsx` に対して、`Header.stories.tsx` を作成します。
```tsx:Header.stories.tsx
import type { ComponentStoryObj, ComponentMeta } from '@storybook/react'
import { spViewport } from '@stories/options/viewports'
import { Header } from '@components/sp/default/shared/Header'

type Story = ComponentStoryObj<typeof Header>

const component = {
  component: Header,
  parameters: { ...spViewport },
}

export default component as ComponentMeta<typeof Header>

export const Mobile: Story = {}
```

- `viewports.ts` というファイルを作成し`spViewport`を参照することで、
`スマホ幅でのスナップショット` が可能になります。
```ts:viewports.ts
export const Viewports = {
  iphone6: {
    width: 375,
    height: 667,
  },
}

export const spViewport = {
  viewport: {
    defaultViewport: 'iphone6',
  },
  screenshot: {
    viewports: {
      iphone6: Viewports.iphone6,
    },
  },
}
```

- 以下コマンド実行で Storybookが立ち上がり、作成したstoryファイル を確認できます。
  - 通常 6006番 で立ち上がりますが、弊社では複数事業にStorybookを入れているので、区別しやすいように番号を変更しています。
```terminal
$ yarn storybook
```
```
http://localhost:6006/
```


## ③ storycap の導入
- 以下コマンドで、storycap と puppeteer を導入。
```terminal
$ yarn add -D storycap puppeteer
```

- package.json に scripts の定義をします。


## ④ reg-suit の導入
- 以下コマンドで、reg-suit を導入。
```terminal
$ yarn add -D reg-suit
```

- reg-suit の初期設定をする
```terminal
$ yarn reg-suit init
```

- コマンド実行すると対話形式が始まり、詳細な設定を選択できます。
- 以下の、必要なplugin を選択
```terminal
# reg-suitの結果 を Gitlabリポジトリ に通知する
# Github を使用している場合は、reg-notify-github-plugin を選択
◉ reg-notify-gitlab-plugin

# スナップショット イメージを取得して AWSのS3 に発行する
◉ reg-publish-s3-plugin

# 指定された値でスナップショット キーを決定する
◉ reg-simple-keygen-plugin

~
```

- S3のバケットを作成済みの場合、バケット名を入力します
```terminal
~

# ここでバケット名を入力（あとからでも設定できます）
? Existing bucket name
●●
```
- `regconfig.json` が自動で追加されます。
- package.json に `scripts: "regression"` の定義をします。（省略）


## ⑤ レポートストレージの設置 と CI/CDへの組み込み
- 上記までの設定完了後、`レポートストレージの設置` と `CI/CDへの組み込み` については、エンジニアに協力してもらいました。
  - CI環境は `Gitlab CI/CD` を利用。
- 本来は、ローカル環境 でVRTの動作検証を行ってからCI/CDに乗せる流れが良いのですが、以下の理由で最初から CI/CD に組み込んでもらう流れになりました。
  - `既に社内の成功事例 がある`ので、同様に展開
  - `AWS の AccessKey や Secretkey` が万が一にも流出すると困る


## ⑥ VRT の動作検証
- ここまでで、VRTの準備が整いました。
- mainブランチ から 新規ブランチ を切り、作成したStoryファイルに対するUIコンポーネントで、`わざと表示差分が出るようなMR` を作成します。
- すると、MRにコメントが追加されます。（実際の表示はこんな感じです。）

![](https://storage.googleapis.com/zenn-user-upload/be82d4c2ef70-20221211.png)

- そして、実際のreport表示 はこんな感じです。

![](https://storage.googleapis.com/zenn-user-upload/1d89674114cd-20221211.png)
- VRTの動作、問題なさそうです。
- 以上で、最小構成でのVRTの導入 が完了しました！！


## はじめてのVRT導入で考えたこと
社内の他サービス では既に VRT が導入されており、その内容を浅く知っていたのですが、
`自分がイチから導入する`というところで、まずどう進めていくのが良いのか を考えました。

**考えた道筋（ゴールまでの意識）**
- `小さなゴール` を置くこと。
- `できそうなところから着手` すること。
- 既にうまくいっている`他事業サービスの設定 を参考にする`こと。
- 自分が手に負えないところについては、`エンジニアと連携する`こと。

**スケジュール感（工数）**
`1ヶ月ほどで完了` できたのですが、他タスクも並行しながらだったのであまり参考にならないと思います。

## VRT導入後 のワークフロー
**既存UIコンポーネント変更 の場合**
① 事業サービス の運用に伴う仕様変更 により、既存UIコンポーネントに変更 が発生する
② 対象のUIコンポーネント に対する Storyファイル を 変更に合わせて更新
③ 修正MR作成後、MRに表示される VRTのコメントとレポート で 変更差分 を確認
④ UI変更内容 を担保しながら、安心感を持ちつつリリース

**新規UIコンポーネント作成 の場合**
① 事業サービス の運用に伴う仕様変更により、新規UIコンポーネント作成 が発生する
② 対象のUIコンポーネント に対する Storyファイル を作成
③ 新規MR作成後、MRに表示される VRTのコメントとレポート で 新規差分 を確認
④ 次回 UIコンポーネント変更リリース時に、安心感を持ちつつリリース


# 残った課題 と 今後のトライ
#### ① タスク工数 が確保できないことによる Storyファイルのカバレッジ担保不足
- 最小構成 で導入したものの、`全ての UIコンポーネントに対するstoryファイルの担保`がまだできておらず、VRT機能だけ がプロダクトに入ったような状態に。。

**→ こちらは、今後しっかりと保守のための工数を確保し、Storyファイルのカバレッジを広げて VRTが機能するようにしていく予定です。**


#### ② 他メンバーへの VRT関連スキル の啓蒙/継承不足
- Storyファイルの作成 や VRTの設定調整できるスキル を持ったメンバーが少なく、他のメインタスクで工数もあまり割けない状況のため、`スキルの啓蒙/継承 が不十分`。

**→ こちらは、VRTに関するWikiを展開し、他のメンバーでも運用できるようにしていく予定です。**


#### ③ report結果 で意図せず差分とみなされるコンポーネントがある
- `意図せず差分として出力されるコンポーネントが存在する`ことにより、毎回差分としてreportされてしまう。

**→ こちらは、Storyファイル や VRTの設定数値 などを調整し、改善していく予定です。**


# まとめ
いかがだったでしょうか？（毎年同じセリフを言ってる気がしますが）
何かお役に立つ情報になっていれば嬉しいです。
ぜひVRTを導入して、**UIが担保できている堅牢なプロダクト** にしていきましょう。


# 参照リンク
- [Storybookとreg-suitで気軽にはじめるVisual Regression Testing](https://blog.wadackel.me/2018/storybook-chrome-screenshot-with-reg-viz/)
- [reg-suit+CircleCIでVisual Regression Test環境の構築](https://zenn.dev/toshiokun/articles/3d7087b84ba1d9)
- [GitLab CI/CD + Storybook + Storycap + reg-suit で画像回帰テストを行う](https://qiita.com/eyuta/items/c11469ec48649ac358fc)
- [安全安心の開発体験のために Visual Regression Testing はじめました。](https://tech.uzabase.com/entry/2022/10/13/152134)