LoginSignup
17
16

More than 5 years have passed since last update.

React + storybook + Backstop.js でビジュアルリグレッションテストする

Last updated at Posted at 2018-05-30

storybook

storybooks/storybook
https://github.com/storybooks/storybook

storybookは各コンポーネントごとに独立したスタイルガイドを生成する機能です。
Reactであれば作成したコンポーネントを快適に閲覧することができます。
demo.gif

ビジュアルリグレッションテストとは

例えばあるコンポーネントを更新した場合、どこかで表示崩れが発生しているかはそのページを見ないと気づけませんでした。
上述したstorybookを利用しAtomic Designなどを取り入れていれば、Templates層を見ることで、ある程度のUIは把握できるようになるでしょう。
ただしページ数が増えてくるとコンポーネントの更新毎にすべてのTemplates層を見ることは煩わしく感じられます。

ビジュアルリグレッションテストは視覚的な回帰テストを指します。
スクリーンショットを撮影し前後の差分を利用するテストです。これによって毎回人が見ることなく、UIの変化をテストすることが可能になります。

Backstop.js

garris/BackstopJS
https://github.com/garris/BackstopJS

ビジュアルリグレッションテストを行うためのツールです。
backstop.jsonという設定ファイルをルートに生成し、オプションなどを追加します。この状態でコマンドを実行するとヘッドレスブラウザが起動しスクリーンショットを撮影します。
テスト時は撮影したスクリーンショットの前後比較を行います。
テスト結果はhtmlとして別途出力され、GUI上で差分は把握することができます。

環境構築

前置きが長くなりましたが、実際に触っていきましょう。
筆者の環境がmacのためwindowsで正しく動作しない可能性があることをご了承お願いします。
また、前提としてNodeはインストールされているものとして勧めます。verは指定しませんがLTSされているverを前提にします。
筆者がyarnを使っている都合でコマンドはyarnで書いています。

ディレクトリ構造

.storybook
    - config.js
src
    - Components
        - Caption
            - index.js
            - index.stories.js
.babelrc

パッケージのインストール

styled-componentsは別のツールに変えても問題ありません。
Backstop.jsだけはグローバルインストールが必要です。

$ yarn add react react-dom styled-components -S
$ yarn add @storybook/react -D
$ yarn add babel-core babel-preset-env babel-preset-react babel-preset-stage-0 -D
$ npm i backstopjs -g

設定ファイル

babel

{
    "presets": [
        "env",
        "react",
        "stage-0"
    ]
}

storybook

storybookの設定ファイルは.storybook/config.jsで行います。
以下のように記述することで./src/Components内に存在する.stories.jsで終わるファイルをすべて走査します。
これでコンポーネントが増えても自動的にstorybookに追加されるようになります。

.storybook/config.js
import React from 'react';

const req = require.context("../src/Components", true, /.stories.js$/);

function loadStories() {
    req.keys().forEach((filename) => req(filename));
}

configure(loadStories, module);

package.json

scriptsはこんな感じにします。それぞれの項目は後述します。

package.json
...
"scripts": {
    "storybook": "start-storybook -p 6006",
    "spec:visual": "backstop reference",
    "test:visual": "backstop test",
    "approve:visual": "backstop approve",
}
...

コンポーネントの作成

コンポーネントは以下のように記述します。

./src/Components/Caption/index.js
import React from 'react';
import styled from 'styled-components';

const CaptionEl = styled.h1`
    font-size: 1.6rem;
    color: #333;
`;

const Caption = ({...props}) => <CaptionEl {...props} />;
export default Caption;

続いてstorybookを作るためのファイルを更新します。

./src/Components/Caption/index.stories.js
import React from 'react';
import {storiesOf} from '@storybook/react';

import Caption from './index';

storiesOf('Caption', module).add('default', () => <Caption>Caption is here.</Caption>);

storybookを確認

storybookは以下のコマンドで実行できます。

$ yarn storybook

問題なく起動できれば、http://localhost:6006でサーバーが起動します。アクセスしコンポーネントが表示されていれば成功です。

スクリーンショット 2018-05-30 16.46.45.png

実際にcssなどを触ると更新されることもわかるかと思います。

Backstop.jsの構築

Backstop.jsはグローバルにインストールが必要です。
上述したコマンドでインストール済みであれば以下のコマンドを叩いてイニシャライズしましょう。

$ backstop init

プロジェクトルートにbackstop.jsonという設定ファイルが生成されます。これを以下のようにします。
scenariosのところで何をテストするのかを設定します。URLはstorybookのナビゲーション部分を省いた状態でコンポーネントのみを表示するURLを入力します。

backstop.json
{
  "id": "backstop demo",
  "viewports": [
    {
      "label": "PC",
      "width": 1024,
      "height": 768
    }
  ],
  "onBeforeScript": "puppet/onBefore.js",
  "onReadyScript": "puppet/onReady.js",
  "scenarios": [
      {
          "label": "Caption",
          "url": "http://localhost:6006/iframe.html?selectedKind=Heading&selectedStory=default",
          "misMatchThreshold": 0.0000000001
      }
  ],
  "paths": {
    "bitmaps_reference": "backstop_data/bitmaps_reference",
    "bitmaps_test": "backstop_data/bitmaps_test",
    "engine_scripts": "backstop_data/engine_scripts",
    "html_report": "backstop_data/html_report",
    "ci_report": "backstop_data/ci_report"
  },
  "report": ["browser"],
  "engine": "puppeteer",
  "engineFlags": [],
  "asyncCaptureLimit": 5,
  "asyncCompareLimit": 50,
  "debug": false,
  "debugWindow": false
}

ビジュアルリグレッションテスト

実際にテストしましょう。
backstop.jsはbackstop.jsonscenariosに記載されたコンポーネントのスクリーンショットを撮影します。
そのためまずはstorybookを立ち上げます。

スクリーンショットの撮影

$ yarn storybook

その状態でターミナルのタブを1つ増やし、追加したタブで以下のコマンドを叩きます。

$ yarn spec:visual

これでスクリーンショットが撮影された状態になります。

リグレッションテストの実行

続いてテストコマンドを叩きます。

$ yarn test:visual

スクリーンショットを再度撮影し、前後比較してテストを行います。
差分がないため今回はパスされます。
ここでCaptionコンポーネントを更新してみます。

./src/Components/Caption/index.js
import React from 'react';
import styled from 'styled-components';

const CaptionEl = styled.h1`
    font-size: 1.2rem;
    color: #666; 
`;

const Caption = ({...props}) => <CaptionEl {...props} />;
export default Caption;

再度テストしてみましょう。

$ yarn test:visual

今度はエラーで出てくるはずです。

スクリーンショット 2018-05-30 16.50.42.png

このようにスクリーンショットに差異が出るとツール側でエラーを出してくれます。
例えばAtomic DesignのTemplates層などをこのツールで管理すると、意図しないカラム落ちなどは未然に防ぐことができるようになります。

変更の承認

変更を承認したり、backstop.jsonscenariosなどを追加する場合、スクリーンショットを撮影するために毎回storybookを起動するのは面倒です。
これを回避するためにbackstop approveが用意されています。本プロジェクトでは以下のコマンドです。

$ yarn approve:visual

上記のコマンドでスクリーンショットが更新されるため次回からはエラーが発生しないようになります。

終わりに

このように今まで人が見なければならなかった部分もツールを使うことで大部分を自動化することが可能になっています。
ぜひプロジェクトでも生かしていけるように自分もがんばります〜:baby:

17
16
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
17
16