1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

StorybookでのVRT(Visual Regression Testing) を最小構成で試す

Posted at

はじめに

タイトルの通り、VRT(Visual Regression Testing) をStorybookを用いて最低限の構成で試してみました。
※ 最低限の構成で試したので、プロジェクトに導入する場合はもう少し考慮が必要そうです。。

対象者

  • VRT(Visual Regression Testing) に興味がある
  • Storybookを用いてVRTを導入しようと思っている
  • VRTどんなものか試してみたい

ゴール

↓のようにお試しでレポート出力が見れる状態
image1.gif

環境構築や準備

各バージョンや環境

- storybook/react: 6.3.12
- storycap: 3.1.0
- node: v12.22.0

1. Docker周り

こちらを参考にDockerfileを作成していきます。後ほど使う puppeteer の為に色々入れてます。

FROM node:12.22.0-alpine

RUN apk update && \
    apk add --no-cache \
      git \
      vim \
      chromium \
      nss \
      freetype \
      harfbuzz \
      ca-certificates \
      ttf-freefont \

docker-compose.yml は以下になります。

version: '3.3'
volumes:
  modules_data:
    driver: local
  next_data:
    driver: local

services:
  vrt:
    build: .
    image: xxxx/vrt
    container_name: 'vrt'
    environment:
      - PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
      - PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
    volumes:
      - .:/usr/src
      - modules_data:/usr/src/node_modules
      - next_data:/usr/src/.next
    command: ash -c "yarn install && yarn dev"
    ports:
      - '3000:3000'
      - '6006:6006'
    working_dir: /usr/src

puppeteerの設定用の環境変数 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD
PUPPETEER_EXECUTABLE_PATH を設定しています。

実際の手順の詳細は省きますが、
npx create-next-app@latest --typescript でnextjsのプロジェクトを作成し、起動できるまでにしときます。
(今回 Next.jsのプロジェクトの想定で実施してますが、storybookが使えれば何でも良さそうかと思います。)

2. Storybookに必要なパッケージをインストール

2-1.npx sb init でインストール

$ npx sb init

package.json に追加されたスクリプトやパッケージは以下になります。

  "scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  },
  "devDependencies": {
    "@babel/core": "^7.16.0",
    "@storybook/addon-actions": "^6.3.12",
    "@storybook/addon-essentials": "^6.3.12",
    "@storybook/addon-links": "^6.3.12",
    "@storybook/react": "^6.3.12",
    "babel-loader": "^8.2.3",
  }

また、stories ディレクトリ配下にサンプルが作成されています。まずはこの stories のサンプルでVRTを試してみたいと思います。
早速 yarn storybook でstorybookを起動してみます。
起動後 http://localhost:6006/ にアクセスすると以下のような画面が表示されればOKです。

image2.png

3. storycap をインストール

reg-viz/storycap: A Storybook Addon, Save the screenshot image of your stories via puppeteer.
v3.0.0 から Puppeteer を別途インストールしたものを使うようになったぽいので、
puppeteerも一緒にインストールしておきます。参考

$ yarn add -D storycap puppeteer

以下今回インストールされたパッケージのバージョンになります。

    "puppeteer": "^11.0.0",
    "storycap": "^3.1.0"

package.jsonscript

"storycap": "storycap --serverCmd \"yarn storybook\" http://localhost:6006 --serverTimeout 600000"

を追加し、試しに実行してみます。

$ yarn storycap

成功すると、__screenshots__ ディレクトリに画像が保存されます。
Storycap は simplemanaged の2モードがあり、上記のままだと simple モードで
今回は細かく制御したい場合は managed モードを使うようです。

4. reg-suit をインストール

reg-viz/reg-suit: Visual Regression Testing tool

$ yarn add -D reg-suit

初期設定を行います。

$ yarn reg-suit init --use-yarn
image3.png

↑初回必要なPluginのインストールを選択するのですが、今回はお試しなので reg-publish-s3-plugin だけ選択しました。
後の質問は以下のように回答しました。

? Working directory of reg-suit. .reg # デフォルトの.reg
? Append ".reg" entry to your .gitignore file. Yes
? Directory contains actual images. __screenshots__ # storycapの出力先の__screenshots__を指定
? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0
[reg-suit] info Set up reg-publish-s3-plugin:
? Create a new S3 bucket No # S3のBucketは別途用意するのでNoで名前も空にしました
? Existing bucket name 

ここまでで出来上がった regconfig.json は以下になります。

{
  "core": {
    "workingDir": ".reg",
    "actualDir": "__screenshots__",
    "thresholdRate": 0,
    "addIgnore": true,
    "ximgdiff": {
      "invocationType": "client"
    }
  },
  "plugins": {
    "reg-publish-s3-plugin": {
      "bucketName": "$S3_BUCKET_NAME"
    }
  }
}

※後々作成したバケット名を外部から設定する為に $S3_BUCKET_NAME を指定しています。
また、package.jsonscript"regression": "reg-suit run" を追加しました。

5. S3にreg-suit用のバケット作成

詳細は割愛しますが、今回 reg-suit-sample というバケットを作成して使います。
またreg-suit実行時にS3アクセスのアカウントを指定する為に、docker-compose.ymlにアクセスキー等を追加しました。

    environment:
      AWS_DEFAULT_REGION: ap-northeast-1
      AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
      AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
      S3_BUCKET_NAME: ${S3_BUCKET_NAME}

VRT実施

1. S3が空の状態で実行

$ yarn storycap
$ yarn regression

実行が完了するとS3には以下がアップロードされていました。
※後々出てきますが、この時 key generator plugin を指定していない為、snapshot_日時 で作成されています。

image4.png

yarn regressionで生成された出力にある Report URL にアクセスしてみると以下のレポートが出力されていました。
image5.png

2. 差分が発生するように変更して再度実施

再度実行すると別途snapshotが作成れていました。
image6.png

ただし、レポートを見ても差分が検知されていません。。
よくよくログを見てみると、

[reg-suit] info Skipped to detect the previous snapshot key because key generator plugin is not set up.
[reg-suit] info Skipped to fetch the expected data because expected key is null.

key generator plugin がセットされていないので、比較元のデータを取ってきてくれてないようです。
改めて、reg-simple-keygen-pluginをインストールして再度実施してみたいと思います。

$ yarn add -D reg-simple-keygen-plugin

regconfig.jsonplugins に↓のように追加します。

    "reg-simple-keygen-plugin": {
      "expectedKey": "hoge",
      "actualKey": "fuga"
    },

今回はお試しなので、keyは一度切りで使う前提でセットしています。
プロジェクトでちゃんと使う場合、reg-keygen-git-hash-pluginを使うか、
CIで生成したhash値を使う事になるかと思います。-> こちら

S3のデータも削除しリセットした状態で再度実行します。

初回は actual しか無いので、actualKeyhoge に変更して実施しときます。
image7.png

次は actualKeyfuga に戻して差分が出るように実施します。
出力されたレポートには以下の様に差分が表示され、比較できるようになっています :sparkles:

image1.gif

めでたしめでたし :tada:

。。。で終わりじゃなく storycapmanaged モードを使って
もう少し色々試してみたいと思います。

3. コンポーネントを新規に作成して操作時のキャプチャでVRTを実施する

ただただコンポーネント表示してレイアウト崩れてないかテストする場合は、上記でも事足りそうですが、
ホバーしたり、クリックしたり、何かしら操作した際にコンポーネントが反応する場合のテストも試してみたいと思います。

3-1. ToggleButtonコンポーネントを作成

image8.gif

↑のようにhoverで色が変わって、クリックするとON / OFF が切り替わる誰得なコンポーネントを作成します。
ディレクトリ構成としては以下になります。

├── pages
├── components
│   └── ToggleButton
│       ├── index.css
│       ├── index.stories.tsx
│       └── index.tsx
import React, { useState } from 'react';
import './index.css';

export type ToggleButtonProps = {};

const ToggleButton: React.VFC = () => {
  const [on, setOn] = useState(false);
  return (
    <div style={{ padding: '0.5rem' }}>
      <button className="toggle-button" onClick={() => setOn(!on)}>
        {on ? 'ON' : 'OFF'}
      </button>
    </div>
  );
};

export default ToggleButton;
.toggle-button {
  background-color: aliceblue;
}

.toggle-button:hover {
  background-color: bisque;
}

3-2. Storybookの設定

.storybook/main.js.storybook/preview.js をそれぞれ以下に修正します。

main.js
module.exports = {
  "stories": [
    "../components/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "storycap"
  ]
}
preview.js
import { withScreenshot } from 'storycap';

export const decorators = [
  withScreenshot,
];

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}

次に components/ToggleButton/index.stories.tsx は以下の様に設定しました。

import { Meta, Story } from '@storybook/react';
import React from 'react';
import ToggleButton, { ToggleButtonProps } from '.';

export default {
  title: 'components/ToggleButton',
  component: ToggleButton,
} as Meta;

const Template: Story<ToggleButtonProps> = (args) => <ToggleButton {...args} />;

// Basic
export const Basic: Story<ToggleButtonProps> = Template.bind({});
Basic.parameters = {
  screenshot: {
    variants: {
      hovered: {
        hover: '.toggle-button',
      },
      clicked: {
        click: '.toggle-button',
      },
    },
  },
};
Basic.args = {};

screenshotのvariantsで複数状態を指定できるので今回は hoverclick した状態もキャプチャするようにしました。
この状態で一度S3にアップしときます。
次にhoverした際の色を少し変更して、VRTを実行してみます。

.toggle-button:hover {
  background-color: antiquewhite;
}

↓hover時の微妙な色の違いもちゃんと検知してくれています :sparkles:
image9.png

ちなみに thresholdRate を変えて試してみた所、0.002 以上だと↑の違いは検知できず、0 ~ 0.001 の間だと検知してくれました 。

まとめ

個人的には導入してしまえば、継続的にチェックができるし、導入もすごい大変というわけでも無いので
費用対効果高くて良さそうだなと思いました :sparkles:

今回試した分は以下のリポジトリにアップしてます。
Slowhand0309/vrt-nextjs-storybook-sample: VRT(Visual Regression Testing) project with Next.js, Storybook

参考リンク

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?