Reg-suit+CircleaCI로 Visual Regression Test 환경 구축

Visual Regression Test


Visual Regression Test(VRT)는 말 그대로 시각적인 튜닝 테스트를 수행합니다.
프런트엔드 개발자, 그렇지 않아도 HTML과 CSS의 수정 작업을 해야 하는 엔지니어들은 다음과 같은 문제를 겪지 않겠는가.
  • 어떤 구성 요소의 CSS만 변경된 줄 알았는데 왜 다른 페이지의 레이아웃이 붕괴되었는지 모르겠다
  • 설계의 레이아웃 규칙이 바뀌어 공동으로 사용하는 CSS를 수정해야 하지만 영향을 미치는 구성 요소가 정상적으로 표시되는지 확인하기 어려워 결과는'지원'으로 발표해야 한다
  • 일반적인 논리 조정 테스트라면 자동 테스트 등을 통해 보장할 수 있지만 HTML과 CSS 등의 레이아웃 등 시각적 실현은 사람의 눈에서 예상과 차이가 있는지 확인해야 한다.
    이 번거로운 작업을 최대한 자동화하는 방법은 Visual Regression Test입니다.

    VRT 환경을 구축하면 이런 일을 할 수 있어요.


    후술한reg-suit를 사용하여 VRT 환경을 구축할 때 다음과 같이 이미지를 바탕으로 변경점을 검측할 수 있다.

    변경된 구성 요소 파일 목록이 감지됨



    어떻게 바뀌었는지 여러 가지 방법으로 확인할 수 있어요.






    CSS가 수정할 때마다 모든 구성 요소를 눈으로 확인하는 것보다 예상치 못한 레이아웃 붕괴를 감지할 수 있습니다.

    VRT를 위한 reg-suit


    'VRT를 위하여'라고 쓰여 있지만 정확히 말하면 reg-suit는 이미지의 차이를 비교할 수 있는 도구이다.
    https://github.com/reg-viz/reg-suit
    reg-suit의 규격은 다음과 같다.
  • 지정된 폴더에 구성된 이미지 파일을 S3(또는 Google Cloud Storage)에 저장
  • PullRequest를 만들 때 목표 지점의 이미지와 목표 지점의 이미지 사이의 차이를 비교할 수 있음
  • reg-suit는 1의 규격을 사용하여 촬영 구성 요소의 캡처 도구(후술한storycap 등)와 조합하여 VRT를 실현할 수 있다.

    reg-suit+storycap+CircleaCI 기반 VRT 환경 구축 절차


    VRT 환경 구축 단계는 다음과 같습니다.
  • 목적지 업로드 준비 S3
  • 구성 요소 캡처 가져오기
  • reg-suit의 초기 설정
  • CircleaCI에서 캡처를 획득하여reg-suit를 이용한 S3 업로드 & 이미지 비교
  • 를 실행할 수 있음
  • PR의 제작
  • 업로드 전 S3 준비


    캡처된 이미지를 업로드할 S3 통을 준비합니다.
    S3 물통 만드는 방법은 생략했지만, 공적 접속에 조금 빠진 설정이 있으니 일단 기재해 두자.

    S3 세그먼트에 대한 공통 액세스 설정


    기본적으로 S3 구간의 공적 접근은'모든 공적 접근은 블록'으로 설정되지만, 이 설정을 유지하면'이미지 업로드'와'차이를 확인할 수 있는 HTML 파일 열람'을 할 수 없습니다. ※1

    위의 그림과 같이 일부 공공 접근을 ON으로 설정합니다.
  • "새 액세스 제어 목록(ACL)을 통해 승인된 세그먼트와 객체에 대한 공용 액세스 차단"열기
  • 이미지 업로드 가능
  • Access Control List(ACL)를 통해 승인된 세그먼트 및 객체에 대한 공용 액세스 차단
  • "차분을 확인할 수 있는 HTML 파일 열람"
  • 해당 S3 세그먼트에 액세스할 수 있는 사용자 만들기


    CircleaCI에서 S3에 이미지를 업로드하기 위해 IAM에서 해당 S3 섹션에 액세스할 수 있는 사용자를 만듭니다.
    이번에 정책은 이미지처럼 주어졌다AmazonS3FullAccess. 행운이 좋으면 그에 상응하는 S3에만 Resource를 제한한다.

    제작 시 획득한 사용자 링크ACCESS_KEY_IDSECRET_ACCESS_KEY는 잠시 후 사용할 수 있습니다.

    구성 요소 캡처 가져오기


    reg-suit는 이미지 비교를 하는 도구이기 때문에 캡처된 프로그램 라이브러리를 만드는 데 아무런 문제가 없습니다.
    이번에는 Storybook에서 정의한 구성 요소 촬영 도구 storycap을 사용합니다.
    (※ 이것은 reg-suit와 같은 개발자의 라이브러리)
    https://github.com/reg-viz/storycap
    # puppeteerをインストールするのは、puppeteerを使用してスクリーンショットを撮影するため
    yarn add storycap puppeteer
    
    package.json에서scripts를 정의합니다.
    package.json
      "scripts": {
        "storybook": "start-storybook -p 6006 -c .storybook",
        "screenshot": "storycap -C puppeteer --serverCmd \"start-storybook -p 6006\" http://localhost:6006 --serverTimeout 60000",
      },
    
    두드리기yarn screenshotscreenshots__아래에 storybook에 정의된 구성 요소의 그림이 설정되어 있는지 확인하십시오.

    Storybook 설정


    Storybook 의 설정에 대해 간략하게 설명합니다.
    ※ 전제는 React+Type Script입니다.
    # config.jsの作成
    mkdir .storybook
    touch .storybook/config.js
    
    .storybook/config.js
    import { configure } from '@storybook/react';
    
    // .stories.tsxというファイルをstorybookで認識するように設定
    const req = require.context('../src', true, /\.stories\.tsx$/);
    
    configure(() => {
      req.keys().forEach((filename) => req(filename));
    }, module);
    
    src/Label.tsx
    import { FC, PropsWithChildren } from 'react'
    
    interface Props {
      primary?: boolean
    }
    
    export const Label: FC<Props> = ({
      children,
      primary,
    }: PropsWithChildren<Props>) => {
      return (
        <span
          style={{
            display: 'inline-block',
            padding: '0 3em',
            height: 55,
            borderStyle: 'solid',
            borderWidth: 1,
            borderColor: primary ? 'red' : '#adadad',
            background: primary ? 'red' : '#fff',
            color: primary ? '#fff' : '#363636',
            font: 'normal 14px/55px sans-serif',
          }}
        >
          {children}
        </span>
      )
    }
    
    src/Label.stories.tsx
    import { storiesOf } from '@storybook/react';
    import { Label } from './Label';
    
    storiesOf('Label', module)
      .add('with default style', () => <Label>Default</Label>)
      .add('with primary style', () => <Label primary>Primary</Label>);
    

    yarn screenshot을 친 결과입니다.


    상기 구성 요소를 정의한 후, 두드리기 yarn screenshot 를 하면 다음 그림을 출력합니다.


    reg-suit의 초기 설정을 진행합니다


    reg-suit의 초기 설정을 진행합니다.
    > yarn add reg-suit
    
    > yarn reg-suit init --use-yarn
    # --use-yarnはpluginをインストールする際にyarnの使用を指定するオプション
    
    ? Plugin(s) to install (bold: recommended)
    # デフォルトで選択している下記のプラグインをインストールする
    # reg-keygen-git-hash-plugin : Detect the snapshot key to be compare with using Git hash.,  
    # reg-notify-github-plugin : Notify reg-suit result to GitHub repository, 
    # reg-publish-s3-plugin : Fetch and publish snapshot images to AWS S3.
    # →S3ではなくGoogle Cloud Storageに画像をあげるreg-publish-gcs-pluginというプラグインもあるので、GCSを利用したい場合には変更する
    
    ? Working directory of reg-suit. .reg
    # 特にこだわりなければデフォルトの.regに設定
    
    ? Append ".reg" entry to your .gitignore file. Yes
    # 特にこだわりなければ.gitignoreに追加
    
    ? Directory contains actual images. __screenshots__
    # スクリーンショット作成ツールによるが、storycapは__screenshots__配下に画像を配置するので、__screenshots__を指定する
    
    ? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0
    # 差分検知の精度を変更できるが、取りあえず最大の0に設定。おそらく精度を上げるとパフォーマンスに影響がある。
    
    ? notify-github plugin requires a client ID of reg-suit GitHub app. Open installation window in your browser Yes
    # ブラウザが立ち上がり、プロジェクトのリポジトリを指定すると自動的にClientIDを取得できる
    
    ? This repositoriy's client ID of reg-suit GitHub app <GithubのクライアントID>
    
    [reg-suit] info Set up reg-publish-s3-plugin:
    ? Create a new S3 bucket No
    # 既存のS3を準備していない場合にはYesを選択してもよい、aws-cliで設定しているcredential情報を使ってS3を作成する点に注意
    
    ? Existing bucket name
    # 先ほど作成したS3の名前を入力する
    
    ? Update configuration file Yes
    
    ? Copy sample images to working dir No
    # スクリーンショットをすでにあげているためサンプルの画像は不要
    
    package.json에서scripts "regression"을 정의합니다.
    package.json
      "scripts": {
        "storybook": "start-storybook -p 6006 -c .storybook",
        "screenshot": "storycap -C puppeteer --serverCmd \"start-storybook -p 6006\" http://localhost:6006 --serverTimeout 60000",
        "regression": "reg-suit run",
      },
    

    CircleaCI에서 캡처를 얻을 수 있으며 reg-suit을 통해 S3 업로드 & 이미지 비교


    job의 정의


    .circleci/config.yml에서 실행yarn screenshotyarn regression의job를 정의합니다.
    .circleci/config.yml
    version: 2
    jobs:
      build:
        docker:
          - image: regviz/node-xcb
    
        working_directory: ~/repo
    
        steps:
          - checkout
          - restore_cache:
              keys:
                - v1-dependencies-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
                - v1-dependencies-
    
          - run: yarn
    
          - save_cache:
              paths:
                - node_modules
              key: v1-dependencies-{{ checksum "package.json" }}-{{ checksum "yarn.lock" }}
    
          - run: yarn screenshot
          - run: yarn regression
    

    환경 변수 설정


    S3에 액세스할 수 있도록 프로젝트의 환경 변수AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY를 설정합니다.

    time out 대책


    CircleaCI에서 storycap을 실행하면 time out입니다.

    따라서 서버 Timeout의 옵션에 60000을 설정했습니다.
    (기본값은 20000ms)
    package.json
      "scripts": {
        "screenshot": "storycap -C puppeteer --serverCmd \"start-storybook -p 6006\" http://localhost:6006 --serverTimeout 600000","
      },
    

    PR의 작업.


    이제 CSS 변경으로 인한 레이아웃 차이를 이미지 기반으로 감지하는 메커니즘이 완성되었습니다.
    얼마 전 레이블.tsx의 CSS를 변경하여 PR을 보냅니다.

    다음 설명은 CircleaCI 작업이 완료되면 자동으로 게시됩니다.
    What do the circles mean?에서 설명한 대로
  • 변경된 구성 요소 수
  • 새 구성 요소 수
  • 변경되지 않은 구성 요소 수
  • 삭제된 구성 요소 수
  • 대화 상자.this report를 클릭하면 처음에 설명한 이미지가 나쁜 HTML로 마이그레이션됩니다. 반드시 확인하십시오.

    참고 문헌


    Storybook과 Reg-suit으로 쉽게 시작하는 Visual Regression Testing
    https://blog.wadackel.me/2018/storybook-chrome-screenshot-with-reg-viz/
    GitLabCI/CD+Storybook+Storycap+reg-suit를 이용한 이미지 회귀 테스트
    https://qiita.com/eyuta/items/c11469ec48649ac358fc#1-timed-out

    메모


    ※1
    그나저나 IAM의 정책 설정과는 상관이 없다.
    공개 방문을 허용하지 않고 이미지를 올릴 수 있는 방법을 아는 사람이 있다면 댓글로 남겨주세요.

    좋은 웹페이지 즐겨찾기