手元で動いたので満足していたら「CIに組み込んでください」と言われた
Playwrightのテストを手元で書いて、緑になるところまでは確認できた。満足していたら「これ、CIで毎回自動で回るようにしてもらえますか」と言われる。Playwrightを使い始めて最初にぶつかる壁がここです。
私も長年Selenium WebDriverを主戦場にしてきましたが、SeleniumからPlaywrightへ移行した記事で書いた通り、最近はほとんどPlaywrightです。ローカルで動くテストをGitHub Actionsに載せる作業自体は、そこまで難しくありません。ただし1年目のうちは「あるある」な詰まりどころが3つあります。この記事では、その3つを潰しながら最小構成のワークフローを組み立てます。
まず動かない。ブラウザが入っていないから
ローカルではnpx playwright testが普通に動くので、CIでも同じコマンドを置くだけで動くと思いますよね。ですが、いきなりワークフローにnpx playwright testだけを書くと、たいてい失敗します。
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright test
ChromiumもFirefoxもWebKitもGitHub Actionsのランナーには最初から入っていないので、ブラウザが見つからずエラーになります。ローカルでは一度npx playwright installを実行済みだったので忘れがちですが、CIのランナーは毎回まっさらな環境です。
公式Dockerイメージか、install –with-depsか
ブラウザを用意する方法は大きく2つです。ひとつはnpx playwright install --with-depsをステップに足す方法です。
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
--with-depsを付けると、ブラウザ本体だけでなくUbuntuランナー上で動かすのに必要なOSのライブラリ一式もまとめて入れてくれます。付け忘れると、ブラウザは入っているのに起動できないという別のエラーで詰まるので注意です。
もうひとつは、Microsoft公式が配布しているmcr.microsoft.com/playwrightイメージをコンテナとして使う方法です。
jobs:
test:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.55.0-noble # 執筆時点の最新系列。実際に使うタグは都度確認してください
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright test
このイメージにはブラウザとOS依存パッケージがあらかじめ全部入っているので、インストールのステップ自体が不要です。ただしイメージのタグ(v1.55.0-nobleの部分)とpackage.jsonの@playwright/testのバージョンを一致させる必要があります。ずれるとブラウザと噛み合わず謎のエラーが出るので、迷ったら--with-deps方式から試すのがおすすめです。
ブラウザバイナリをキャッシュする定石と、その罠
ではキャッシュでインストール時間を短縮しましょう。ブラウザのダウンロードは地味に時間がかかるので、毎回律儀にダウンロードするのはもったいない気がしますよね。actions/cacheでブラウザの保存先をキャッシュする定石は次の形です。
- name: Cache playwright binaries
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
- run: npm ci
- run: npx playwright install --with-deps
キーの設計を間違えると、古いブラウザを引き当てる罠にはまります。package-lock.jsonを含めずOS名だけをキーにしていると、Playwrightのバージョンを上げても古いキャッシュがヒットし続け、テストランナーが期待するリビジョンとキャッシュ済みのリビジョンがずれます。結果は「入っているはずなのに起動できない」というさっきの罠と同じ症状です。キーには必ずPlaywrightのバージョン(またはpackage-lock.jsonのハッシュ)を紐づけてください。
正直に書いておくと、Playwright公式は近年「ブラウザバイナリのキャッシュはあまり推奨しない」という立場です。キャッシュの復元時間と素直にダウンロードする時間があまり変わらないうえ、OS依存パッケージのインストールはそもそもキャッシュできないからです。私も試しましたが、体感できるほどの短縮にはならないプロジェクトもありました。
落ちた時にログだけ見ても原因がわからない
ワークフローが動くようになると、次は「CIでだけテストが落ちる。でもログを見ても原因がわからない」という壁です。ローカルなら画面を見ながらデバッグできますが、CIに画面はありません。ログに出るのはエラーメッセージくらいで、ページがどんな状態だったのかは分かりません。
playwright.config.tsでtraceとreporterを設定しておくと、失敗したテストの実行過程を記録として残せます。
// playwright.config.ts
export default defineConfig({
reporter: [['html']],
use: {
trace: 'on-first-retry',
},
});
これで、失敗して自動リトライされた1回目にtraceファイルが保存されます。あとはこのtraceとHTMLレポートをactions/upload-artifactで成果物として残すだけです。
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ failure() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 7
if: ${{ failure() }}を付けているので、失敗した時だけレポート一式をアップロードします。毎回成功時もアップロードしてストレージを圧迫する必要はありません。
ダウンロードしたレポートをローカルで開く
GitHub ActionsのUI上でArtifactsからzipをダウンロードし、展開してローカルで開きましょう。
npx playwright show-report playwright-report
これでローカルのshow-reportと同じ画面です。失敗したテストからtraceも開けます。以前traceをCLIだけで開く記事の通り、CIのtraceも同じコマンドで開けます。
npx playwright show-trace test-results/xxxx/trace.zip
trace viewerではクリックした瞬間のDOMのスナップショットやネットワーク通信まで時系列で追えます。ログだけでは分からなかったものが画面の状態として見えるので、ここまでやって初めて原因調査がまともにできます。
あわせて覚えておきたいCLIオプション
ワークフローYAML・キャッシュ・失敗時の証跡保存という3点は揃いました。CIで落ちたテストを手元でどう再現するかでも詰まりやすいので、CLIオプションを一通りまとめた記事も合わせて読んでおくとスムーズです。私自身、最初にCIへ組み込んだ時は「ブラウザが入っていない」「キャッシュが古いブラウザを引く」「落ちてもログしか残らない」の3つを順番に踏みました。この順番で潰せば1年目でも迷わないはずです。
まとめ
PlaywrightをGitHub Actionsで自動実行する時は、まずブラウザを用意する方法(--with-depsか公式イメージか)を決め、キャッシュを入れるならバージョンに紐づいたキー設計にすること。そして失敗した時のためにtraceとHTMLレポートをartifactとして必ず残しておくこと。この3点を押さえておけば、CIに載せる作業でつまずく箇所はかなり減らせます。
まずは--with-depsだけの最小構成から試してみてください。組んでみて別のエラーにぶつかった方は、ぜひコメントで教えてください。私も試行錯誤中です(正直、キャッシュの効果測定はまだ自分の中でも決着していません)。


コメント