🎍

Playwright × MSW × OpenAPI で E2E 事始め

2023/07/13に公開

E2E テストを導入する上でハードルになるのが「テストデータ」と「環境のセットアップ」かと思います。
MSW, OpenAPI を使って比較的スムーズに E2Eテスト(Playwright)を導入できたので、参考にした記事を中心にまとめます。

Playwright の導入

公式に従いインストールしました。
https://playwright.dev/docs/intro

Playwright MSW の導入

playwright-mswを入れることで、playwright が起動するブラウザで MSW によるインターセプトを有効にすることができます。

以下を参考に設定しました。
https://github.com/valendres/playwright-msw
https://blog.tech-monex.com/entry/2023/05/12/092240

デフォルトの handlers を用意する

E2E テストを実行する上で、ベースとしては全ての API フェッチに対して Mock が効いていた方が便利かなと思い、デフォルトで設定する hanlders を用意しました。

デフォルトの handler のレスポンスは、OpenAPI の example から生成できるようにしました。

/* src/mocks/handlers.ts */
import { getHandlerFromOpenapi } from '~/mocks/utils'

export const handlers = [
  getHandlerFromOpenapi('get', '/api/examples', 200),
]
/* src/mocks/utils.ts */
import { rest } from 'msw'
// @ts-ignore
import schema from '~/openapi.json'

const exampleValue = (
  method: RestMethods,
  path: string,
  status: number
) => {
  const searchPath = path.replace(':id', '{id}')

  const resContent = (schema as any).paths[searchPath][method].responses[status]
    .content['application/json']

  return resContent.examples['Example 1']?.value || {}
}

export const getHandlerFromOpenapi = (
  method: RestMethods,
  path: string,
  status: number
) => {
  const response = exampleValue(method, path, status)
  return getHandler(method, path, status, response)
}

上記で設定した handlers を読み込むよう設定して完了です。

/* src/e2e/testUtils.ts */

import { MockServiceWorker, createWorkerFixture } from 'playwright-msw'
import { test as base, expect } from '@playwright/test'
import { handlers } from '~/mocks/handlers'

const test = base.extend<{
  worker: MockServiceWorker
}>({
  worker: createWorkerFixture(handlers),
})

export { test, expect }

test を書く

localhost:3000/exmaples のビジュアルリグレッションテストを書いてみました。

/* src/e2e/example.spec.ts */
import { test, expect } from '~/e2e/testUtils'

test('examples', async ({ page }) => {
  await page.goto('/examples')
  await expect(page).toHaveScreenshot({ fullPage: true })
})

screenshot の画像ファイル名は、デフォルトではテストケース名が反映されるようになっています。
これだとテストケース名を変更するたびにテストが落ちてしまうので、以下の記事を参考に変更しました。

/* playwright.config.ts */
  ...
  snapshotPathTemplate: '{snapshotDir}/{testFilePath}-screenshots/{arg}-{projectName}{ext}'
  ...

https://seyyyy.com/blog/vrt

細かいですが、Jest も使っている場合 Playwright のテストファイルも読み込んでしまうため、ignore 設定が必要です。

/* jest.config.js */
testPathIgnorePatterns: ['<rootDir>/src/e2e'],

今後取り組むこと

以上の設定で Github Actions でも実行したところ、フォントが読み込まれずに、差分が発生してテストが落ちてしまいました。
解消でき次第、こちらにもワークアラウンドを記載予定です。

Discussion