私はいつも、ユニット テストが実行される (そして合格する) のを見るのが大好きでした。ユニット テストは高速で、テストに合格すると、個々の部分が想定どおりに動作するという確信が得られます。逆に、ブラウザーのエンドツーエンド テストの作成と実行に非常に時間がかかるため、その優先順位付けに苦労することがよくありました。
幸いなことに、エンドツーエンドのブラウザ内テスト用のツールは、ここ数年で大幅に改善され、高速化しています。また、ヘッドレス ブラウザのセットアップにより、ブラウザ テストを CI の一部として実行できます。
最近、Heroku CI 内でヘッドレス Chrome を使用してブラウザ内テストを自動化する方法について説明しているHeroku ブログ投稿を見つけました。Heroku にはヘッドレス Chrome をインストールするビルドパックがあり、CI パイプラインでテストに呼び出すことができます。
ブログ投稿のサンプル設定は、 PuppeteerとJestでテストされた React アプリでした。これは素晴らしいスタートですが、Puppeteer の代わりにPlaywright を使用したらどうなるでしょうか? それは可能ですか?
調べてみることにしました。結局のところ、Playwright でも同じことができるのです! そこで、Heroku CI で使用されるヘッドレス Chrome ブラウザで Playwright テストを実行するために必要な手順をまとめました。この記事では、セットアップの手順を説明します。
エンドツーエンドのテストでは、ユーザーがブラウザで実際にアプリを操作する方法をキャプチャし、完全なワークフローを検証します。Playwright では、Chrome、Firefox、Safari でのテストにより、このプロセスを非常にシームレスに実行できます。もちろん、CI でブラウザ テストのフル スレートを実行するのはかなり負荷がかかるため、ヘッドレス モードが役立ちます。
Heroku のChrome for Testing ビルドパックは、Heroku アプリに Chrome をインストールするので、非常に軽量なセットアップで Heroku CI で Playwright テストを実行できます。
ちょうど試してみたかったので、Heroku ブログ投稿で最初に参照された GitHub リポジトリをフォークしました。アプリケーションは、リンク、テキスト入力、送信ボタンを備えたシンプルな React アプリでした。テストは 3 つありました。
とても簡単です。あとは、Puppeteer と Jest の代わりに Playwright を使用するようにコードを変更するだけです。あ、npm の代わりにpnpmも使いたいと思いました。こちらがフォークした GitHub リポジトリへのリンクです。
コードを変更するために私が実行した手順を見ていきましょう。私はheroku-examples
リポジトリと同一のフォークされたリポジトリから始めました。
私は npm ではなく pnpm を使いたかったのです。(個人的な好みです。) そこで、まず次の操作を実行しました。
~/project$ corepack enable pnpm ~/project$ corepack use pnpm@latest Installing [email protected] in the project… … Progress: resolved 1444, reused 1441, downloaded 2, added 1444, done … Done in 14.4s ~/project$ rm package-lock.json ~/project$ pnpm install # just to show everything's good Lockfile is up to date, resolution step is skipped Already up to date Done in 1.3s
次に、Puppeteer と Jest を削除し、Playwright を追加しました。
~/project$ pnpm remove \ babel-jest jest jest-puppeteer @testing-library/jest-dom ~/project$ $ pnpm create playwright Getting started with writing end-to-end tests with Playwright: Initializing project in '.' ✔ Do you want to use TypeScript or JavaScript? · JavaScript ✔ Where to put your end-to-end tests? · tests ✔ Add a GitHub Actions workflow? (y/N) · false ✔ Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? (Y/n) · false ✔ Install Playwright operating system dependencies (requires sudo / root - can be done manually via 'sudo pnpm exec playwright install-deps')? (y/N) · false Installing Playwright Test (pnpm add --save-dev @playwright/test)… … Installing Types (pnpm add --save-dev @types/node)… … Done in 2.7s Writing playwright.config.js. Writing tests/example.spec.js. Writing tests-examples/demo-todo-app.spec.js. Writing package.json.
また、 package.json
から Jest 構成セクションも削除しました。
Playwright テストは、Chrome、Firefox、Safari で実行できます。Chrome に焦点を当てていたため、生成されたplaywright.config.js
ファイルのprojects
セクションから他のブラウザーを削除しました。
/* Configure projects for major browsers */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, // // { // name: 'webkit', // use: { ...devices['Desktop Safari'] }, // }, ], …
元のコードにはsrc/tests/puppeteer.test.js
に Puppeteer テスト ファイルがありました。そのファイルをtests/playwright.spec.js
に移動しました。次に、Playwright の規則を使用するようにテストを更新しました。これは非常にきれいにマッピングされました。新しいテスト ファイルは次のようになりました。
const ROOT_URL = 'http://localhost:8080'; const { test, expect } = require('@playwright/test'); const inputSelector = 'input[name="name"]'; const submitButtonSelector = 'button[type="submit"]'; const greetingSelector = 'h5#greeting'; const name = 'John Doe'; test.beforeEach(async ({ page }) => { await page.goto(ROOT_URL); }); test.describe('Playwright link', () => { test('should navigate to Playwright documentation page', async ({ page }) => { await page.click('a[href="https://playwright.dev/"]'); await expect(page.title()).resolves.toMatch('| Playwright'); }); }); test.describe('Text input', () => { test('should display the entered text in the text input', async ({ page }) => { await page.fill(inputSelector, name); // Verify the input value const inputValue = await page.inputValue(inputSelector); expect(inputValue).toBe(name); }); }); test.describe('Form submission', () => { test('should display the "Hello, X" message after form submission', async ({ page }) => { const expectedGreeting = `Hello, ${name}.`; await page.fill(inputSelector, name); await page.click(submitButtonSelector); await page.waitForSelector(greetingSelector); const greetingText = await page.textContent(greetingSelector); expect(greetingText).toBe(expectedGreeting); }); });
start-server-and-test
削除し、代わりに Playwright の webServer を使用します。 React アプリをテストするには、まず別のプロセスで ( http://localhost:8080
で) 起動してから、テストを実行する必要がありました。これは、Puppeteer を使用する場合でも Playwright を使用する場合でも同じです。Puppeteer の場合、Heroku の例ではstart-server-and-test
パッケージが使用されていました。
ただし、テストを実行する前にアプリを起動するように Playwright を設定できます。これは非常に便利です。
プロジェクトからstart-server-and-test
削除しました。
~/project$ pnpm remove start-server-and-test
playwright.config.js
で、下部の webServer セクションのコメントを解除し、次のように変更しました。
/* Run your local dev server before starting the tests */ webServer: { command: 'pnpm start', url: 'http://127.0.0.1:8080', reuseExistingServer: !process.env.CI, },
次に、元のpackage.json
ファイルからtest:ci
スクリプトを削除しました。代わりに、テスト スクリプトは次のようになりました。
"scripts": { … "test": "playwright test --project=chromium --reporter list" },
Playwright は、テストに使用する最新のブラウザ バイナリをインストールします。そのため、ローカル マシンでは、Playwright の Chromium バージョンをインストールする必要がありました。
~/project$ pnpm playwright install chromium Downloading Chromium 130.0.6723.31 (playwright build v1140) from https://playwright.azureedge.net/builds/chromium/1140/chromium-linux.zip 164.5 MiB [====================] 100%
注: Heroku の Chrome for Testing ビルドパックは、テストに使用するブラウザをインストールします。Playwright が独自のブラウザをインストールするのに時間とリソースを費やすのではなく、そのブラウザを使用するように CI を設定します。
これで準備は完了です。次はローカルでテストを試してみる番です。
~/project$ pnpm test > playwright test --project=chromium --reporter list Running 3 tests using 3 workers ✓ 1 [chromium] > playwright.spec.js:21:3 > Text input > should display the entered text in the text input (911ms) ✘ 2 [chromium] > playwright.spec.js:14:3 > Playwright link > should navigate to Playwright documentation page (5.2s) ✓ 3 [chromium] > playwright.spec.js:31:3 > Form submission > should display the "Hello, X" message after form submission (959ms) ... - waiting for locator('a[href="https://playwright.dev/"]') 13 | test.describe('Playwright link', () => { 14 | test('should navigate to Playwright documentation page', async ({ page }) => { > 15 | await page.click('a[href="https://playwright.dev/"]'); | ^ 16 | await expect(page.title()).resolves.toMatch('| Playwright'); 17 | }); 18 | });
ああ、その通りです。アプリ内のリンクが Puppeteer ではなく Playwright のドキュメントに移動することを期待するようにテストを変更しました。19 行目のsrc/App.js
更新する必要がありました。
<Link href="https://playwright.dev/" rel="noopener"> Playwright Documentation </Link>
さて、もう一度テストを実行する時間になりました...
~/project$ pnpm test > playwright test --project=chromium --reporter list Running 3 tests using 3 workers ✓ 1 [chromium] > playwright.spec.js:21:3 > Text input > should display the entered text in the text input (1.1s) ✓ 2 [chromium] > playwright.spec.js:14:3 > Playwright link > should navigate to Playwright documentation page (1.1s) ✓ 3 [chromium] > playwright.spec.js:31:3 > Form submission > should display the "Hello, X" message after form submission (1.1s) 3 passed (5.7s)
テストに合格しました! 次は、Heroku CI に移行するときです。
Heroku ブログ投稿の指示に従って、Heroku CI パイプラインでアプリをセットアップしました。
Heroku で新しいパイプラインを作成し、フォークした GitHub リポジトリに接続しました。
次に、アプリをステージングに追加しました。
次に、 「テスト」タブに移動して、 「Heroku CI を有効にする」をクリックしました。
最後に、 app.json
ファイルを変更して、 npm test:ci
呼び出すように設定されたテスト スクリプトを削除しましたpackage.json
ファイルからtest:ci
スクリプトはすでに削除してありましたpackage.json
のtest
スクリプトが使用されるようになり、Heroku CI はデフォルトでそのスクリプトを検索するようになりました。
Chrome for Testing ビルドパックを使用するように設定された私のapp.json
ファイルは次のようになります。
{ "environments": { "test": { "buildpacks": [ { "url": "heroku-community/chrome-for-testing" }, { "url": "heroku/nodejs" } ] } } }
コードを GitHub にプッシュすると、Heroku CI でテスト実行がトリガーされました。
テスト実行は失敗しましたが、心配していませんでした。Playwright の設定がいくつか必要になることはわかっていました。
テスト ログを調べてみると、次のことがわかりました。
Error: browserType.launch: Executable doesn't exist at /app/.cache/ms-playwright/chromium-1140/chrome-linux/chrome
Playwright は Chrome ブラウザ インスタンスを探していました。CI テスト セットアップの一部として、 playwright install chromium
コマンドを使用してインストールできました。しかし、それでは Chrome for Testing ビルドパックの目的が台無しになってしまいます。Chrome はすでにインストールされていたので、それを適切に指定するだけで済みました。
Heroku のテスト設定ログを振り返ってみると、次の行が見つかりました。
Installed Chrome dependencies for heroku-24 Adding executables to PATH /app/.chrome-for-testing/chrome-linux64/chrome /app/.chrome-for-testing/chromedriver-linux64/chromedriver Installed Chrome for Testing STABLE version 130.0.6723.91
つまり、私が使用したいブラウザは/app/.chrome-for-testing/chrome-linux64/chrome
にありました。Playwright でそこを検索するだけで済みます。
注:ここでの細かい詳細に興味がない場合は、このセクションをスキップして、下にある完全なapp.json
をコピーしてください。これで、Heroku CI で Playwright を起動して実行するために必要なものが揃います。
Playwright のドキュメントで、すべてのブラウザ インストールにカスタムの場所を使用したかどうかを Playwright に伝える環境変数を設定できることが分かりました。その環境変数はPLAYWRIGHT_BROWSERS_PATH
です。そこから始めることにしました。
app.json
では、次のようにenv
変数を設定します。
{ "environments": { "test": { "env": { "PLAYWRIGHT_BROWSERS_PATH": "/app/.chrome-for-testing" }, ...
CI でのテストで何が起こるかを確認するために、コードを GitHub にプッシュしました。
予想通り、再び失敗しました。ただし、ログ エラーには次のように表示されました。
Error: browserType.launch: Executable doesn't exist at /app/.chrome-for-testing/chromium-1140/chrome-linux/chrome
かなり近づきました。私はこうすることにしました:
mkdir -p "$PLAYWRIGHT_BROWSERS_PATH/chromium-1140/chrome-linux"
ln -s \ $PLAYWRIGHT_BROWSERS_PATH/chrome-linux64/chrome \ $PLAYWRIGHT_BROWSERS_PATH/chromium-1140/chrome-linux/chrome
しかし、これが将来にわたって有効かどうかは心配でした。 最終的に、Playwright は新しいバージョンの Chromium を使用するようになり、 chromium-1140
フォルダーのようには見えなくなります。 Playwright がどこに表示されるかはどうすればわかるのでしょうか?
そのとき、ブラウザのインストールの予行演習ができることを発見しました。
~/project$ pnpm playwright install chromium --dry-run browser: chromium version 130.0.6723.31 Install location: /home/alvin/.cache/ms-playwright/chromium-1140 Download url: https://playwright.azureedge.net/builds/chromium/1140/chromium-linux.zip Download fallback 1: https://playwright-akamai.azureedge.net/builds/chromium/1140/chromium-linux.zip Download fallback 2: https://playwright-verizon.azureedge.net/builds/chromium/1140/chromium-linux.zip
「インストール場所」の行は重要です。PLAYWRIGHT_BROWSERS_PATH PLAYWRIGHT_BROWSERS_PATH
設定すると、次のようになります。
~/project$ PLAYWRIGHT_BROWSERS_PATH=/app/.chrome-for-testing \ pnpm playwright install chromium --dry-run browser: chromium version 130.0.6723.31 Install location: /app/.chrome-for-testing/chromium-1140 ...
それが私が望んでいたことです。ちょっとしたawk
マジックを使って、これを実行しました:
~/project$ CHROMIUM_PATH=$( \ PLAYWRIGHT_BROWSERS_PATH=/app/.chrome-for-testing \ pnpm playwright install --dry-run chromium \ | awk '/Install location/ {print $3}' ) ~/project$ echo $CHROMIUM_PATH /app/.chrome-for-testing/chromium-1140
これらすべてを理解したら、あとはapp.json
にtest-setup
スクリプトを追加するだけです。 PLAYWRIGHT_BROWSERS_PATH
はすでにenv
に設定されているため、スクリプトは少しシンプルになります。最終的なapp.json
ファイルは次のようになります。
{ "environments": { "test": { "env": { "PLAYWRIGHT_BROWSERS_PATH": "/app/.chrome-for-testing" }, "buildpacks": [ { "url": "heroku-community/chrome-for-testing" }, { "url": "heroku/nodejs" } ], "scripts": { "test-setup": "CHROMIUM_PATH=$(pnpm playwright install --dry-run chromium | awk '/Install location/ {print $3}'); mkdir -p \"$CHROMIUM_PATH/chrome-linux\"; ln -s $PLAYWRIGHT_BROWSERS_PATH/chrome-lin ux64/chrome $CHROMIUM_PATH/chrome-linux/chrome" } } } }
test-setup
何をするのかを簡単に説明します。
PLAYWRIGHT_BROWSERS_PATH
を考慮して、 playwright install -- dry-run
とawk
を使用して、Playwright が Chrome ブラウザを検索するルート フォルダを決定します。これをCHROMIUM_PATH
変数の値として設定します。
CHROMIUM_PATH/chrome-linux
に新しいフォルダー (および必要な親フォルダー) を作成します。これは、Playwright がchrome
バイナリを検索する実際のフォルダーです。
そのフォルダーに、Chrome の Heroku ビルドパックのインストール ( /app/.chrome-for-testing/chrome-linux64/chrome
) を指すシンボリック リンクを作成します。
更新したapp.json
ファイルを使用すると、Playwright はビルドパックから Chrome インストールを使用できるようになります。もう一度テストを実行するときが来ました。
成功!
test-setup
スクリプトは期待どおりに実行されました。
Playwright はchrome
バイナリにアクセスしてテストを実行し、合格しました。
私の Web アプリケーションのエンドツーエンドのテストは、それほど面倒ではなくなってきているので、ますます優先しています。最近では、Playwright も頻繁に使用しています。Playwright は柔軟で高速です。そして、Heroku CI の Chrome for Testing ビルドパックを使用して Playwright を稼働させるための作業 (私と皆さんのために!) が完了したので、ブラウザー自動化テスト スイートの構築を再び開始できます。
このウォークスルーのコードは私のGitHub リポジトリで入手できます。
楽しいコーディングを!