🦛

playwrightでnext.jsのcoverageまで取りたい

2022/12/26に公開

playwrightでnext.jsのテストを実行してcoverageまで取るのがわりと情報揃ってなかったのでまとめる。

手順の流れ

今回は、下記の手順を踏んでいく

    1. テストの準備対応
    • @playwright/testの代わりにplaywright-test-coverageを利用する
    1. カバレッジモードのnextの設定
    • nycを利用するnext.jsの起動モードを準備する(next.config.jsの設定)
    1. playwrightとnycをつなぐ
    • playwrightからの起動時にnycを利用した起動モードを利用する

1. テストの準備対応

とりあえず普通にnext.js側のファイルを用意

$ yarn add next
// pages/index.ts

import Head from 'next/head'
import React, { useState } from 'react'

export default function Home() {
  return (
    <Box>
      <Head>
        <title>Index Page</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Box>Hello</Box>
      <ToggleButton />
    </Box>
  )
}

次にplaywrightの準備。istanbulを利用してくれるplaywright-test-coverageも利用する

$ yarn add @playwright/test playwright-test-coverage

テストはまず簡素に訪問するものを作成。

// import { expect, test } from "@playwright/test"
import { expect, test } from "playwright-test-coverage"

test("index", async ({ page }) => {
  await page.goto("/") // URLはplaywright.config.jsで指定する予定なので、`/`のみとする(後述)
  await expect(page).toHaveTitle("Index Page")
  await page.screenshot()
})

ここでカバレッジのために@playwright/testの代わりにplaywright-test-coverageを利用する

2. カバレッジモードのnextの設定

カバレッジに必要なnycと、babelでコードも対応させる必要があるのでそのあたりもインストールする

$ yarn add nyc babel-loader babel-plugin-istanbul

next.jsはbabel.confg.jsを追加すると勝手にそちらを読んでくれるのだが、これを行うとSWCが無効化されてしまう。カバレッジのためだけにSWCが無効化されるのも気持ち悪いので、next.config.jsで切り替えれるようにする。

今回はenvとしてCOVERAGE=1などがある場合にカバレッジモードで起動するようにしてみる

// next.config.js
module.exports = () => {
  if (process.env.COVERAGE) {
    const coverageConfig = {
      distDir: ".next_coverage",
      webpack: (config, options) => {
        config.module.rules.push({
          test: /\.(js|jsx|ts|tsx)$/,
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
            plugins: ['istanbul'],
            presets: ["next/babel"],
          },
        })
        return config
      }
    }
    return coverageConfig
  }
  return {}
}

webpackの設定はnext.jsのDiscussionを参考にした。

distDirは通常の起動と分けておかないとたまにおかしな挙動をしてしまうので分離しておく

今回はカバレッジの起動コマンドもscriptに定義しておくことにする。ポートは何でも良いが、今回は例として3001を利用する

// package.json
  "scripts": {
    "dev": "next dev",
    "dev:coverage": "COVERAGE=1 nyc next dev -p 3001",
  }

nyc.config.jsも設定しておく

module.exports = {
  all: true,
  include: ["src"],
  reporter: ["html", "json", "text"]
}

カバレッジ関連のファイルを無視したので、.gitignoreも設定する

.next_coverage/
.nyc_output/
coverage/

3. playwrightとnycをつなぐ

playwrightにはwebServerという設定があるので、これを利用する

// playwright.config.js
import type { PlaywrightTestConfig } from '@playwright/test'

const config: PlaywrightTestConfig = {
  webServer: {
    command: 'yarn dev:coverage',
    url: 'http://localhost:3001/',
    reuseExistingServer: false,
  },
  use: {
    baseURL: 'http://localhost:3001/',
  },

}

export default config

こうするとplaywrightを実行時に勝手にdev:coverageを実行してそちらを利用してくれる。
もしカバレッジを取らないplaywright実行もしたい場合はこちらもenv等を受け取って切り替えるようなことをすると良いだろう

最後に実行コマンドを追加

// package.json
  "scripts": {
    // ...
    "e2e:coverage": "playwright test; nyc report"
  }

テスト実行後にnyc reportを実行しないとカバレッジが作成されないので、最後にこれを実行するように設定しておく。

$ yarn e2e:coverage

あとはカバレッジファイルを開けば閲覧出来るはず

$ open coverage/index.html
GitHubで編集を提案

Discussion