🌏

ぼくのかんがえたNext.jsの構成

commits25 min read 2

はじめに

普段開発している Next.js プロジェクトの構成がなかなかいけてるんじゃないかということで、その構成を公開しちゃおうというお話。ほんとはタイトルをぼくがかんがえたさいきょうのNext.jsの構成にしたかったけどひよりました

2021/3/25 時点のモノです。package のバージョンのアップデート等によりここで記載されている方法が間違っている場合があります

(今回の記事を作るにあたり改めて一から Next.js のリポジトリ作ったら husky のバージョン上がってたり、eslint-config-prettier の v8 系になって config の書き方ちょっと変わってたり、時代は移り変わるのです・・)

意外と手順書いていくと長くなったので一部coming soonになっているものは確固たる意思を持って、随時追記します

更新履歴

  • 2021/04/01 css modules が storybook で上手く呼べてなかったので修正、あと storybook のバージョンアップ
  • 2021/03/31 なんと続編(僕のかんがえたフロントエンドアーキテクチャ)が出ました
  • 2021/03/26 snapshot の方法追記
  • 2021/03/26 ビジュアルリグレッションテストの方法追記

https://zenn.dev/kichion/articles/fddf0eb35ffa2a

記事のターゲット

  • Next.js の構成が気になる人
  • 自分用の手順書メモでもある

構成

()に使ってる理由とか用途とか書いてます

  • Next.js
  • TypeScript (いわずもがな)
  • Storybook (コンポーネント駆動で開発できるから)
  • ESLint (いわずもがな)
  • Prettier (いわずもがな)
  • Husky (push や commit 時に lint や format や test のコマンドが実行できる)
  • lint-staged (git の stage に入ったファイルに対して lint や format ができる)
  • Jest (Unit テスト + Snapshot)
  • Tailwind CSS(賛否両論あるかもですが個人的に書いてて楽しいので採用)
  • scaffold コマンド(コンポーネントのテンプレートの自動生成)の追加
  • Renovate(依存 package の定期的な更新) coming soon[1]
  • storycap + reg-suit(ビジュアルリグレッションテスト)
  • Cypress (E2E テスト)

環境

package.json
  "dependencies": {
    "next": "10.0.9",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@storybook/addon-essentials": "6.2.1",
    "@storybook/addon-links": "6.2.1",
    "@storybook/addon-postcss": "2.0.0",
    "@storybook/addon-storyshots": "6.1.21",
    "@storybook/react": "6.2.1",
    "@testing-library/react": "11.2.5",
    "@types/jest": "26.0.21",
    "@types/node": "14.14.35",
    "@types/react": "17.0.3",
    "@types/react-dom": "17.0.3",
    "@typescript-eslint/eslint-plugin": "4.19.0",
    "@typescript-eslint/parser": "4.19.0",
    "autoprefixer": "10.2.5",
    "babel-jest": "26.6.3",
    "eslint": "7.22.0",
    "eslint-config-prettier": "8.1.0",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-react": "7.23.1",
    "eslint-plugin-simple-import-sort": "7.0.0",
    "husky": "5.2.0",
    "jest": "26.6.3",
    "jest-watch-typeahead": "0.6.1",
    "lint-staged": "10.5.4",
    "postcss": "8.2.8",
    "postcss-nested": "5.0.5",
    "prettier": "2.2.1",
    "reg-keygen-git-hash-plugin": "0.10.15",
    "reg-notify-github-plugin": "0.10.15",
    "reg-notify-slack-plugin": "0.10.15",
    "reg-publish-s3-plugin": "0.10.15",
    "reg-suit": "0.10.15",
    "storycap": "3.0.3",
    "tailwindcss": "2.0.4",
    "typescript": "4.2.3"
  }

実際のコード

https://github.com/nus3/next-boilerplate

Let's try!

  1. npx create-next-app {project-name}
  2. yarn policies set-version (yarn のバージョン指定)
  3. 生成された.yarnrc にsave-prefix ""の追加(インストールする package のバージョンを固定する)
  4. .node-versionの追加
  5. mkdir src && mv pages src && mv styles src(srcディレクトリに諸々を移動する)
  6. yarn add --dev typescript @types/react @types/react-dom @types/node typescript 周りを入れる
  7. src 配下のファイルを tsx に変更する + .babelrc + tsconfig.json
  8. eslint + prettier を入れる
  9. jestを入れる
  10. lint-staged + huskyを入れる
  11. Tailwind CSSを入れる
  12. Storybookを入れる
  13. storyshotsを入れて snapshot テストを実行する
  14. storycap + reg-suitを入れてビジュアルリグレッションテストを実行する

7.src 配下のファイルを tsx に変更する + .babelrc + tsconfig.json

.babelrc
.babelrc
{
  "presets": ["next/babel"]
}
tsconfig.json
tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src",
    "target": "es5",
    "module": "esnext",
    "jsx": "preserve",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "noEmit": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "exclude": ["node_modules", "deployments", ".next", "out"],
  "include": [
    "next-env.d.ts",
    "globals.d.ts",
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.js",
    "test/**/*.ts",
    "test/**/*.tsx"
  ]
}
`_app.tsx`
src/pages/_app.tsx
import 'styles/globals.css'

import { NextPage } from 'next'
import { AppProps } from 'next/dist/next-server/lib/router/router'

const MyApp: NextPage<AppProps> = ({ Component, pageProps }: AppProps) => {
  return <Component {...pageProps} />
}

export default MyApp
`index.tsx`
src/pages/_app.tsx
import { NextPage } from 'next'
import Head from 'next/head'
import styles from 'styles/Home.module.css'

const Home: NextPage = () => {
  return (
    <div className={styles.container}>
      {/* ... */}
    </div>
  )
}

export default Home

js から tsx に書き直してる最中に下記部分で型のエラーが出るかもですが
import styles from 'styles/Home.module.css'

yarn devとかするとnext-env.d.tsが生成されてエラー解消される

8. eslint + prettier を入れる

eslint 周りで必要なもの + 追加したい eslint rule + prettier のパッケージをインストール

yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-prettier eslint-plugin-react eslint-plugin-import eslint-plugin-simple-import-sort prettier
.eslintrc.json

好みです
rule はその時その時で必要なものを入れましょう

.eslintrc.json
{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint", "simple-import-sort", "import"],
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "env": {
    "es6": true,
    "browser": true,
    "jest": true,
    "node": true
  },
  "rules": {
    "react/react-in-jsx-scope": 0,
    "react/display-name": 0,
    "react/prop-types": 0,
    "@typescript-eslint/explicit-function-return-type": 0,
    "@typescript-eslint/explicit-member-accessibility": 0,
    "@typescript-eslint/indent": 0,
    "@typescript-eslint/member-delimiter-style": 0,
    "@typescript-eslint/no-explicit-any": 0,
    "@typescript-eslint/no-var-requires": 0,
    "@typescript-eslint/no-use-before-define": 0,
    "@typescript-eslint/no-unused-vars": [
      2,
      {
        "argsIgnorePattern": "^_"
      }
    ],
    "no-console": [
      2,
      {
        "allow": ["warn", "error"]
      }
    ],
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "import/no-unresolved": "off",
    "sort-imports": "off",
    "react/self-closing-comp": [
      "error",
      {
        "component": true,
        "html": true
      }
    ]
  }
}

.prettierrc

好みです

.prettierrc
{
  "singleQuote": true,
  "semi": false,
  "trailingComma": "all"
}

vscode 使ってたら vscode の設定入れる

.vscode/settings.json
.vscode/settings.json
{
  "editor.tabSize": 2,
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  "css.validate": false
}

プロジェクトで必要な vscode の拡張もあれば用意しとくと深切

.vscode/extensions.json
.vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
  ]
}

9. jestを入れる

yarn add --dev @testing-library/react @types/jest babel-jest jest jest-watch-typeahead
jest.config.js
jest.config.js
module.exports = {
  roots: ['<rootDir>'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'jsx'],
  testPathIgnorePatterns: [
    '<rootDir>[/\\\\](node_modules|.next)[/\\\\]',
    '<rootDir>/test/Storyshots.test.ts',
  ],
  transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$'],
  transform: {
    '^.+\\.(js|ts|tsx)$': 'babel-jest',
  },
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname',
  ],
  moduleNameMapper: {
    '\\.(styl|css|less|scss)$': '<rootDir>/test/__mocks__/styleMock.js',
    '\\.(gif|ttf|eot|svg|png)$': '<rootDir>/test/__mocks__/fileMock.js',
  },
  moduleDirectories: ['node_modules', 'src'],
}
snapshot テストで mock 対応するので先に設定しとく

jest.config.jsmoduleNameMapperのところ

test/__mocks__/fileMock.js
module.exports = 'test-file-stub'
test/__mocks__/styleMock.js
module.exports = {}
package.json のコマンド追加

linter と formatter のコマンドも追加するの忘れたのでここで記載する

package.json
  "scripts": {
    "type-check": "tsc --pretty --noEmit",
    "format": "prettier --write .",
    "lint": "eslint src --ext ts --ext tsx",
    "test": "jest",
    "test-all": "yarn lint && yarn type-check && yarn test"
  },
サンプルのテストで動作確認する
test/pages/index.test.tsx
import '@jest/globals'

describe('jest 動作確認', () => {
  test('true toBeTruthy', () => {
    expect(true).toBeTruthy()
  })
})

yarn testで jest 実行されるかどうか確認する

10. lint-staged + huskyを入れる

stage に上がってるファイルに対して lint かけてくれるlint-stagedと git のコミットやプッシュ前のときにコマンドを実行してくれるhuskyを入れる

yarn add --dev husky lint-staged
lint-staged の設定を package.json に追加
package.json
  "lint-staged": {
    "*.@(ts|tsx)": [
      "yarn lint",
      "yarn format"
    ]
  },
husky の設定追加

yarn husky install

今回は pre-commit と pre-push の設定だけしとく

  • コミット前に stage にあるファイルに対して lint と format を実行する
  • push 前に test と 型チェック を実行する
.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged
.husky/pre-push
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn test & yarn type-check

11. Tailwind CSSを入れる

公式のドキュメント通りに進めればいける

  1. yarn add --dev tailwindcss postcss autoprefixer postcss-nested
  2. yarn tailwindcss init -p

tailwindcss を読み込む

globals.css
src/styles/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

vscode の setting.json で"css.validate": falseすることで@tailwindのエラーを消す(正しいかどうかは定かではない)

tailwind.config.js

後々、js で動的な class 名を生成する場合(下記の classnames)は safelist の設定をしとく
purge の設定て下記のようなコードは tailwindcss 側で読み込まれない感じなので safelist で purge しないでって設定をする
https://tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html

const spanClass = classnames(`text-${fontSize}`, `text-${color}`);
tailwind.config.js
module.exports = {
  purge: {
    content: ['./src/components/**/*.tsx', './src/pages/**/*.tsx'],
    options: {
      // https://purgecss.com/safelisting.html#patterns
      safelist: {
        standard: [/^bg-/, /^text-/],
      },
    },
  },
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}
postcss.config.js

好み
sass みたいにネストした書き方ができるpostcss-nestedを追加

postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
+    'postcss-nested': {},
  },
}

src/pages/index.tsxとかで適当な要素のclassNameを変えてみて、ちゃんと tailwindcss が使えるか確認する

src/pages/index.tsx
- <h1 className={styles.title}>
-   Welcome to <a href="https://nextjs.org">Next.js!</a>
- </h1>
+ <h1 className="text-bg-500">
+   Welcome to <a href="https://nextjs.org">Next.js!</a>
+ </h1>
.vscode/extensions.json

tailwindcss の拡張が便利なので入れる

.vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
+    "bradlc.vscode-tailwindcss",
  ]
}

12. Storybookを入れる

Error: PostCSS plugin tailwindcss requires PostCSS 8.

tailwindcss(v2)を使う場合 postcss は v8 が必要だが storybook の 6.1 系では postcss が v7 系なのでエラーが発生するので6.2.0-alpha.23 + @storybook/addon-postcssをインストールしている

参考にした issue

yarn add -D @storybook/react@6.2.0-alpha.23 @storybook/addon-links@6.2.0-alpha.23 @storybook/addon-essentials@6.2.0-alpha.23 @storybook/addon-postcss

.storybook配下に必要な設定を入れる

.storybook の設定
  • addon-postcss 入れることで postcss8 対応
  • tsconfig の baseUrl の対応するために webpack.config を上書き
.storybook/main.js
const path = require('path')

module.exports = {
  stories: [
    '../src/components/**/**/*.stories.mdx',
    '../src/components/**/**/*.stories.@(js|jsx|ts|tsx)',
  ],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-links',
    {
      name: '@storybook/addon-postcss',
      options: {
        postcssLoaderOptions: {
          implementation: require('postcss'),
        },
      },
    },
  ],
  webpackFinal: async (baseConfig) => {
    // NOTE: tsconfigのbaseUrlの対応
    baseConfig.resolve.modules = [
      path.resolve(__dirname, '..', 'src'),
      'node_modules',
    ]

    // HACK: 根本解決ではない気もする
    // HACK: エラー処理もおまじない程度
    // NOTE: デフォルトではcss modulesは読み込まれないので読み込まれるように設定する
    // ref: https://qiita.com/s6n/items/f64b2c4be580e1fc1cb8#css-%E3%81%8C%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BE%E3%82%8C%E3%81%AA%E3%81%84%E5%95%8F%E9%A1%8C
    const cssRule = baseConfig.module.rules.find(
      (rule) => String(rule.test).indexOf('css') !== -1,
    )
    if (!cssRule) return { ...baseConfig }

    // NOTE: 対象から.module.cssファイルを外す
    cssRule.test = /^.*(?<!\.module)\.css$/
    const cssLoader = cssRule.use.find(
      (u) => String(u.loader).indexOf('css-loader') !== -1,
    )
    if (cssLoader) {
      cssLoader.options = {
        // NOTE: css-loaderを呼ぶ前に適用されるローダーの数 1だとpostcss-loaderを適用することになる
        importLoaders: 1,
      }
    }

    // NOTE: postcss-loaderはaddon-postcssのものをそのまま使う
    const postcssLoader = cssRule.use.find(
      (u) => String(u.loader).indexOf('postcss-loader') !== -1,
    )

    if (postcssLoader) {
      baseConfig.module.rules.push({
        // NOTE: .module.cssファイルのみが対象
        test: /\.module\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
              // NOTE: css modulesを有効にする
              modules: true,
            },
          },
          postcssLoader,
        ],
      })
    }

    return { ...baseConfig }
  },
}

Next.js の router を storybook に載せるコンポーネントで使う場合の mock

.storybook/newRouterMock.js
import * as nextRouter from 'next/router'

nextRouter.useRouter = () => ({
  route: '/',
  pathname: '/',
  push: () => {},
  prefetch: () => new Promise((resolve, reject) => {}),
})

postcss の config を root 直下から取得

.storybook/postcss.config.js
const postcssConfig = require('../postcss.config')
const usePlugins = {}

// NOTE: Using Next.js postcss config
// Convert a plugins format for postcss-loader.
postcssConfig.plugins.forEach((plugin) => {
  // Has options?
  if (Array.isArray(plugin) && plugin.length === 2) {
    usePlugins[plugin[0]] = plugin[1]
  } else {
    usePlugins[plugin] = {}
  }
})

module.exports = {
  plugins: usePlugins,
}

tailwindcss の読み込みや addon の設定(addon の設定は好みです)

.storybook/preview.js
import style from '../src/styles/globals.css'
import router from './newRouterMock'

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
  layout: 'fullscreen',
  backgrounds: {
    default: 'light',
    values: [
      { name: 'light', value: '#F7F8FA' },
      { name: 'dark', value: '#314565' },
      { name: 'white', value: '#FFFFFF' },
      { name: 'black', value: '#000000' },
    ],
  },
}
package.json にコマンド追加
package.json
  "scripts": {
+    "storybook": "start-storybook -p 9009 -s ./public",
+    "build-storybook": "build-storybook -s ./public"
  },

13. storyshotsを入れて snapshot テストを実行する

  1. storybook の snapshot 用の addon を入れる yarn add -D @storybook/addon-storyshots
  2. snapshot テストの実行ファイルを作成する
  3. jest の config を修正
  4. package.json にコマンド追加
  5. snapshot テストが動くか確認する
snapshot テストの実行ファイルを作成する

公式ドキュメントの通り

test/test.storyshots.ts
import initStoryshots, {
  multiSnapshotWithOptions,
} from '@storybook/addon-storyshots'

initStoryshots({
  integrityOptions: { cwd: __dirname },
  test: multiSnapshotWithOptions(),
})

jest の config を修正

unit テスト時の config と snapshot の config を分ける
何を分けたかというとtestMatchプロパティで実行するテストファイルを分けた感じ

unit テスト用の config

jest.config.js
module.exports = {
  roots: ['<rootDir>'],
  moduleFileExtensions: ['ts', 'tsx', 'js', 'json', 'jsx'],
  testPathIgnorePatterns: ['<rootDir>[/\\\\](node_modules|.next)[/\\\\]'],
  transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$'],
  transform: {
    '^.+\\.stories\\.tsx$': '@storybook/addon-storyshots/injectFileName',
    '^.+\\.(js|ts|tsx)$': 'babel-jest',
  },
  testMatch: ['<rootDir>/**/?(*.)(spec|test).(ts|js)?(x)'],
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname',
  ],
  moduleNameMapper: {
    '\\.(styl|css|less|scss)$': '<rootDir>/test/__mocks__/styleMock.js',
    '\\.(gif|ttf|eot|svg|png)$': '<rootDir>/test/__mocks__/fileMock.js',
  },
  moduleDirectories: ['node_modules', 'src'],
}

snapshot の config

jest.storyshots.config.js
const baseConfig = require('./jest.config')

module.exports = {
  ...baseConfig,
  name: 'Storyshots',
  displayName: 'storyshots',
  testMatch: ['<rootDir>/test/test.storyshots.ts'],
  moduleNameMapper: {
    ...baseConfig.moduleNameMapper,
  },
}
package.json にコマンド追加
package.json
  "scripts": {
    "test": "jest",
    "test-all": "yarn lint && yarn type-check && yarn test",
+   "storyshots": "NODE_ENV=test jest --config ./jest.storyshots.config.js",
+   "update-storyshots": "NODE_ENV=test jest --config ./jest.storyshots.config.js --updateSnapshot",
  },

yarn storyshotsで前回の snapshot とコンポーネントの内容が変わってないかテストし、
yarn update-storyshotsで snapshot を更新する

14. storycap + reg-suitを入れてビジュアルリグレッションテストを実行する

ビジュアルリグレッションテストを導入することでコンポーネントの見た目が意図しない変更をしていないかチェックできる(ライブラリのアップデートとかで)
仕組みとしては storycap で storybook に登録しているコンポーネントのスクショをとり、reg-suit で前回のスクショと比較して見た目が変わっていないかをチェックしてくれる

  1. storycap をインストール yarn add --dev storycap
  2. package に screenshot コマンドを追加
  3. screenshot を実行してみる
  4. reg-suit をインストール
  5. reg-suit の github app を入れる
  6. slack の webhook の用意
  7. aws cli で s3 のバケットの作成ができるようにしておく
  8. reg-suit initで初期設定
  9. reg-suit runで ビジュアルリグレッションテストを実行してみる

package に screenshot コマンドを追加
package.json
  "scripts": {
    "storybook": "start-storybook -p 9009 -s ./public",
    "build-storybook": "build-storybook -s ./public",
+   "screenshot": "storycap http://localhost:9009 --serverCmd 'start-storybook -p 9009 -s ./public'"
  },

yarn screenshotを実行すると root 直下に__screenshots__が作成され storybook のスクショが保存される


reg-suit のインストール

yarn add --dev reg-suit

reg-suit の github app を入れて、Repository accessからビジュアルリグレッションテストを実行したいリポジトリを選択する

You can get client IDs here.の here から client id をメモる

reg-suit initで初期設定

今回は github で作成したプルリクのコメントにビジュアルリグレッションテストの結果を追加してほしいのとスクショを S3 に保存、Slack 通知は試してみたかったので下記の 4 つを選択した

`reg-suit init` での一問一答
[reg-suit] info version: 0.10.15
? Plugin(s) to install (bold: recommended)  reg-keygen-git-hash-plugin : Detect the snapshot key to be compare with using Git hash.,  re
g-notify-github-plugin : Notify reg-suit result to GitHub repository,  reg-publish-s3-plugin : Fetch and publish snapshot images to AWS
S3.,  reg-notify-slack-plugin : Notify reg-suit result to Slack channel.
[reg-suit] info Install dependencies to the local directory. This procedure takes some minutes, please wait.
? Working directory of reg-suit. .reg
? Append ".reg" entry to your .gitignore file. Yes
? Directory contains actual images. __screenshots__ {スクショのファイルが保存されるところの指定}
? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0
[reg-suit] info Set up reg-notify-github-plugin:
? notify-github plugin requires a client ID of reg-suit GitHub app. Open installation window in your browser No {github appのreg suit管理画面からclient-id取得してたらNoでよし}
? This repositoriy's client ID of reg-suit GitHub app {client id貼り付け}
[reg-suit] info Set up reg-notify-slack-plugin:
? Incoming webhook URL {slackのwebhook url貼り付け}
? Send test message to this URL ? No
[reg-suit] info Set up reg-publish-s3-plugin:
? Create a new S3 bucket Yes {aws cliでs3のバケットを作成できる権限があればよしなにバケットを作ってくれる}
[reg-publish-s3-plugin] info Create new S3 bucket: {バケット名}
? Update configuration file Yes
? Copy sample images to working dir No

yarn を使ってる場合は init すると必要な依存関係が npm としてインストールされるので改めて yarn でインストールし直す
yarn add --dev reg-keygen-git-hash-plugin reg-notify-github-plugin reg-publish-s3-plugin reg-notify-slack-plugin

__screenshots__.regは gitignore しておく

reg-suit initを実行するとregconfig.jsonが生成される
また s3 にバケットが生成されている

うまくいかない場合は大抵、aws cli 周りが原因
(s3 バケットを作る権限がない aws アカウントで aws cli を実行してるとか)

__screenshots__配下にスクリーンショットがある状態でreg-suit runを実行する
うまくいけば s3 にスクリーンショットが保存され、webhook を指定した slack のチャネルにビジュアルリグレッションテスト結果の通知がくる

package に ビジュアルリグレッションテストのコマンドを追加
package.json
  "scripts": {
+    "visual-test": "reg-suit run --quiet"
  },

今回は public のリポジトリにしている関係上、regconfig.jsonに client-id や slack の webhook を記載していないので github のプルリクを作成した際にreg-suit runのレポートがコメントされるかを検証していない。
ただ、正しく client-id の設定と、github app を登録した上で、CI(circleci など) でreg-suit run --quietすると添付のようなレポートをコメントしてくれる

参考: circleci の config.yml

circleci の context に aws のアクセスキーとか登録してる
今回はhotfix|staging|mainブランチ以外であればビジュアルリグレッションテストを実行するような書き方

.circleci/config.yml
orbs:
  aws-cli: circleci/aws-cli@1.4.0
executors:
  with_browsers:
    working_directory: /home/circleci/src/
    docker:
      - image: circleci/node:14.16.0-browsers

jobs:
  visual_regression:
    executor: with_browsers
    steps:
      - checkout
      - attach_workspace:
          at: .
      - run:
          name: install jp fonts
          command: sudo apt update && sudo apt-get install fonts-ipafont-gothic fonts-ipafont-mincho
      - run:
          name: screenshots
          command: yarn screenshot
      - run:
          name: regression
          command: yarn visual-test

workflows:
  run_all:
    jobs:
      - visual_regression:
          name: visual regression testing for stage
          context: {circleciのcontext}
          requires:
            - build
          filters:
            tags:
              ignore: /.*/
            branches:
              ignore: /(hotfix(\/.+)|staging|main)?/

脚注
  1. そのうち追記します・・確固たる意思を持って・・ ↩︎

GitHubで編集を提案

この記事に贈られたバッジ

Discussion

ログインするとコメントできます