Nuxt.jsのサイトにPercyを導入してレンダリング差分を視覚化する

# はじめに
[Percy](https://percy.io) はWebページのレンダリング結果の差分を視覚化して、レビューを可能とするサービスです。GitHubと連携させることで、PRを作る度に所定のブランチ(デフォルトでは`master`)との差分を抽出し、その結果をPRのステータスへと反映させることができます。そのため、HTMLのマークアップやCSSなどを変更した際に、意図しないリグレッションが発生していないかどうかをチェックするのに有効です。

例えば、CSSを変更したことによって、一部テキストのフォントカラーが変わったとしましょう。左が変更前、右が変更後です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/36a0b67d-391d-9e67-412e-5c4919813b47.png)

Percyを使うと、この両者のレンダリング結果の差分を抽出し、次のように異なる箇所をハイライト表示させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/af94f83a-7a80-85d4-377b-4bc2b0a69a41.png)

Percyは [月あたり5000以下のスナップショットであれば無料で利用可能](https://percy.io/pricing) なので、小規模なプロジェクトであれば導入も難しくありません。そこでこの記事では、Percyを用いた差分チェックを可能とする環境の構築方法を説明します。

なお、この記事で紹介するコード、およびセットアップ内容は、[GitHubレポジトリ](https://github.com/Tsuyoshi84/nuxt-percy-sample) で公開しています。

## 技術要素
この記事では、以下の技術要素を用います。

- Nuxt.js / Vue.js
- Jest / Puppeteer
- Yarn
- CircleCI

また、上記の技術要素は既にある程度把握していることを前提とし、個々の詳細な説明は割愛します。

# セットアップ
## Nuxt.jsサイトの構築

まずはNuxt.jsのサイトを構築します。[公式サイトのInstall方法](https://nuxtjs.org/guide/installation/) に従うことで、以下のようなページを表示するNuxt.jsのプロジェクトが作成できるはずです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/d747f80f-1773-4250-292a-948c764e7cf0.png" width="500" alt="Nuxt.js Top page">

Nuxt.jsのプロジェクトを構築後、適切なGitHubレポジトリにソースコードをpushしてください。

## テストの構築

### Puppeteerのインストール

以下のコマンドをターミナルで実行して、Puppeteer、 Percyの各種パッケージをインストールします。

```shell
$ yarn add -D jest jest-puppeteer @percy/puppeteer
```

### Jest/Puppeteerの設定ファイルの追加

以下のようなPuppeteerによるテストのためのJest設定ファイルを配置します。

```e2e/jest.config.js
module.exports = {
  moduleFileExtensions: ["js", "json"],
  testRegex: "(/__tests__/.*|(\\.|/)(e2e))\\.js$",
  testPathIgnorePatterns: ["/node_modules/"],
  preset: "jest-puppeteer"
};
```

また、jest-puppeteerの設定ファイルも以下のように追加します。

```jest-puppeteer.config.js
module.exports = {
  server: {
    command: 'yarn start',
    port: 3000
  },
  preset: 'jest-puppeteer'
}
```

### Puppeteerのテストの追加

Puppeteerによるテスト実行、および、Percyのスナップショットを取得するためのテストファイルを配置します。

```e2e/website.e2e.js
const puppeteer = require("puppeteer");
const { percySnapshot } = require("@percy/puppeteer");

describe("Web site", () => {
  const BASE_URL = "http://localhost:3000";
  let browser;
  let page;

  beforeAll(async () => {
    browser = await puppeteer.launch();
    page = await browser.newPage();
  });

  afterAll(async () => {
    await browser.close();
  });

  describe("top page", () => {
    beforeAll(async () => {
      await page.goto(BASE_URL);
    });

    it("should show page", async () => {
      await expect(page.title()).resolves.toMatch("nuxt-percy-sample");
      await percySnapshot(page, "Top page");
    });
  });
});
```

上記テストに記述された `percySnapshot` が、Percyのスナップショットを取得する関数です。第３パラメータにオプションを渡すことで、以下のようにスナップショット取得時のサイズなどを設定することもできます。

```javascript
await percySnapshot(page, 'Top page', { widths: [768, 992, 1200] });
```

`percySnapshot` のオプションの詳細については、 [ドキュメント](https://docs.percy.io/docs/puppeteer#section-configuration) を参照してください。

### package.jsonへのスクリプトの追加

先ほど追加したテストを実行可能とするため、 `package.json` に、以下のスクリプトを追加します。

```package.json
  "scripts": {
    "test:e2e": "jest -c e2e/jest.config.js e2e",
    "test:percy": "percy exec -- yarn test:e2e",
  }
```

## Percyのセットアップ

次にPercyのセットアップを行います。以降の説明は、既にPercyのアカウントとOrganizationが作成してある前提で進めます。

### プロジェクトの作成

まずは、現在作成しているコードに対応するPercyのプロジェクトを作ります。プロジェクトの名前は任意のものを指定できますが、わかりやすいようにGitHubのレポジトリ名と同様にしておくのが良いでしょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/171872d5-fc4a-81a8-0d0e-f77628208ca4.png" width="500" alt="Create Percy Project">

プロジェクトを作成すると、プロジェクト固有のPercyトークンが表示されます。(プロジェクトの設定ページからも確認することができます) これは後のCircleCIのセットアップ作業で使用します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/58c57e7e-2423-f419-a4dc-16df98ed3f79.png" width="300" alt="Percy Token">

### GitHub Appのインストール

Percyのチェック結果がGitHub PRのステータスに反映されるようにするには、PercyのGitHub Appをインストールする必要があります。そのため、 [PercyのGitHub Appのページ](https://github.com/apps/percy) からインストールを行ってください。

### GitHubレポジトリの連携

先ほど作成したPercyプロジェクトにGitHubレポジトリを紐つけます。Percyプロジェクトの `Integrations` タブから、以下のようにGitHubレポジトリを選択してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/220b361b-07f8-173b-4107-60c0644de165.png" width="400" alt="GitHub setup">

## CircleCIのセットアップ

最後に、CircleCIのセットアップを行います。

### 設定ファイルの配置

CircleCIのconfigファイルを `.circleci` ディレクトリの中に配置してください。なお、CircleCIではPercy用のOrb、 [percy/agent](https://circleci.com/orbs/registry/orb/percy/agent) が提供されているので、それを利用します。

```yml:.circleci/config.yml
version: 2.1

orbs:
  percy: percy/agent@0.1.3

jobs:
  build_test:
    docker:
      - image: circleci/node:12.3-browsers
    working_directory: ~/repo
    steps:
      - checkout
      - run: yarn install
      - run: yarn build
      - run: yarn test:percy

workflows:
  version: 2
  build:
    jobs:
      - build_test
      - percy/finalize_all:
          requires:
            - build_test
```

### CircleCIプロジェクトのセットアップ

上記のconfigファイルをGitHubレポジトリにpushしたら、次にCircleCIをセットアップします。CircleCIプロジェクトの設定は [公式ドキュメント](https://circleci.com/docs/2.0/enable-checks) に従って実施するものとし、ここでは詳細を割愛します。

### 環境変数の設定

先の手順で生成したPercyのトークンをCircleCIに登録します。CircleCIのプロジェクト設定を開いて `Environment Variables` を選択し、 `PERCY_TOKEN` という環境変数名でトークンを設定してください。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/9b7b7871-663a-d80a-08b3-d2b8a2a13cff.png" width="500" alt="Set Percy Token">

また、 [ドキュメント](https://docs.percy.io/docs/circleci#section-environment-variables) に従って `PERCY_PARALLEL_TOTAL` に `-1` という値も設定しておきます。

# CIの実行

ここまでの作業で、セットアップが完了しました。コードを `master` ブランチにpushしていれば、CircleCIが実行されてPercyへとレンダリング結果がホストされているはずです。

それでは、適当なPRを作って、CircleCI、Percyによるチェック処理を実行させてみましょう。ここでは、下の画像のように、 `My laudable Nuxt.js project` というテキストのフォントカラーを赤に変更してみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/44390f31-af78-04d1-3992-f43d16a828db.png" width="500" alt="Top page">

この変更をpushしてGitHub PRを作ると、PRのステータスにPercyのチェック結果が表示され、レビューが必要であることが示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/95e908a9-b01d-447e-ec1c-0d8cb208fe04.png" width="700" alt="GitHub status">

上記の `Details` からPercyへと移動すると、差分を確認することができます。ここでは、フォントカラーを変更した部分がハイライト表示され、レンダリング結果に差分が生じていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12152/b39d6415-d336-1715-2e3f-cd54afd196cd.png)

Percyが検出したこの差分をApproveすると、GitHub PRのステータスもOKとなります。

# まとめ

この記事では、Nuxt.jsで構築したサイトのレンダリング差分をPercyでチェックするための環境構築についてまとめました。ここではごく基本的な設定しかしていませんが、ドキュメントを見るとわかるように、Storybookとの連携やアニメーションへの対処など、Percyは様々な機能を提供しています。レンダリング結果のリグレッションをチェックする上では有用なサービスだと思うので、導入を検討してみるといいかもしれません。

# 参考
- [Percy - Docs - Puppeteer](https://docs.percy.io/docs/puppeteer)
- [Jest - Puppeteer](https://jestjs.io/docs/en/puppeteer)
- [CircleCI ORB - percy/agent](https://circleci.com/orbs/registry/orb/percy/agent)