私はいつも単体テストが実行される (そして合格する) のを見るのが大好きでした。それらは高速であり、テストに合格すると、私の個々の部分が想定どおりに動作するという保証が得られます。逆に、ブラウザのエンドツーエンド テストの作成と実行が恐ろしく遅いため、優先順位を付けるのに苦労することがよくありました。
幸いなことに、ブラウザ内でエンドツーエンドのテストを行うためのツールは、長年にわたってはるかに優れ、高速になってきました。また、ヘッドレス ブラウザをセットアップすると、CI の一部としてブラウザ テストを実行できます。
最近、私は Heroku CI 内のヘッドレス Chrome を使用したブラウザ内テストの自動化について説明している、この Heroku ブログ投稿を見つけました。 Heroku にはヘッドレス Chrome をインストールするビルドパックがあり、CI パイプラインでテストのために呼び出すことができます。
ブログ投稿のセットアップ例は、Puppeteer と Jest でテストされた React アプリでした。それは素晴らしいスタートです…しかし、Puppeteer の代わりに Playwright を使用したらどうなるでしょうか?可能でしょうか?
私は調査することにしました。結局のところ、 — はい、Playwright でもこれを行うことができます。そこで、Heraku CI で使用されるヘッドレス Chrome ブラウザで Playwright テストを実行するために必要な手順をキャプチャしました。この投稿では、セットアップの手順を説明します。
エンドツーエンドのテストでは、ユーザーがブラウザーで実際にアプリをどのように操作するかをキャプチャし、完全なワークフローを検証します。 Playwright は、Chrome、Firefox、Safari でのテストを行うことで、このプロセスを非常にシームレスにします。もちろん、CI でブラウザー テストをすべて実行するとかなり負荷がかかるため、ヘッドレス モードが役立ちます。
Heraku の 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 pnpm@9.12.3 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 ファイルのプロジェクト セクションから他のブラウザを削除しました:
/* 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); }); });
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 のドキュメントに移動できるようにテストを変更しました。 src/App.js の 19 行目を更新する必要がありました:
<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)
テストは合格しました!次に、Heraku CI に移行します。
私は Heroku ブログ投稿の手順に従って、アプリを Heroku CI パイプラインにセットアップしました。
Heraku で新しいパイプラインを作成し、フォークした GitHub リポジトリに接続しました。
次に、アプリをステージングに追加しました。
次に、テスト タブに移動し、Heraku CI を有効にする をクリックします。
最後に、app.json ファイルを変更して、npm test:ci を呼び出すように設定されたテスト スクリプトを削除しました。 package.json ファイルから test:ci スクリプトをすでに削除していました。 package.json 内のテスト スクリプトが使用されるようになり、Heraku CI はデフォルトでそのスクリプトを検索します。
Chrome for Testing ビルドパックを使用するようにした私の app.json ファイルは次のようになります:
~/project$ corepack enable pnpm ~/project$ corepack use pnpm@latest Installing pnpm@9.12.3 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
コードを GitHub にプッシュすると、Heraku CI でのテスト実行がトリガーされました。
試運転は失敗しましたが、心配はしていませんでした。 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.
Playwright は Chrome ブラウザのインスタンスを探していました。 CI テスト設定の一部として、playwright install chromium コマンドを使用してインストールできました。しかし、それは Chrome for Testing ビルドパックの目的全体を無効にしてしまいます。 Chrome はすでにインストールされています。それを適切に指す必要があっただけです。
Heraku のテスト設定ログを振り返ると、次の行が見つかりました:
/* Configure projects for major browsers */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, // // { // name: 'webkit', // use: { ...devices['Desktop Safari'] }, // }, ], …
つまり、私が使用したいブラウザは /app/.chrome-for-testing/chrome-linux64/chrome にありました。 Playwright に探してもらうだけです。
注: ここでの核心的な詳細に興味がない場合は、このセクションをスキップして、完全な app.json を下にコピーしてください。これにより、Heraku CI で Playwright を起動して実行するために必要なものが得られます。
Playwright のドキュメントで、すべてのブラウザーのインストールにカスタムの場所を使用したかどうかを Playwright に伝える環境変数を設定できることがわかりました。その環境変数は PLAYWRIGHT_BROWSERS_PATH です。そこから始めることにしました。
app.json で、次のように環境変数を設定します。
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); }); });
CI でのテストで何が起こるかを確認するためにコードを GitHub にプッシュしました。
予想通り、また失敗しました。ただし、ログ エラーには次のことが示されていました:
~/project$ corepack enable pnpm ~/project$ corepack use pnpm@latest Installing pnpm@9.12.3 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
これでかなり近づいてきました。私はこれをやろうと決めました:
~/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.
/* Configure projects for major browsers */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, // // { // name: 'webkit', // use: { ...devices['Desktop Safari'] }, // }, ], …
しかし、これが将来性があるかどうかが心配でした。最終的に、Playwright は新しいバージョンの Chromium を使用することになり、chromium-1140 フォルダーには表示されなくなります。 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); }); });
その「インストール場所」行は重要でした。そして、PLAYWRIGHT_BROWSERS_PATH を設定すると、次のようになります:
~/project$ pnpm remove start-server-and-test
それが私が望むものです。ちょっと気の利いた魔法を使って、こんなことをしてみました:
/* Run your local dev server before starting the tests */ webServer: { command: 'pnpm start', url: 'http://127.0.0.1:8080', reuseExistingServer: !process.env.CI, },
以上のことを理解したら、あとはテストセットアップ スクリプトを app.json に追加するだけです。 PLAYWRIGHT_BROWSERS_PATH は既に env に設定されているため、スクリプトはもう少し単純になります。これが私の最後の app.json ファイルでした:
"scripts": { … "test": "playwright test --project=chromium --reporter list" },
test-setup の機能について簡単に説明します。
PLAYWRIGHT_BROWSERS_PATH を考慮して、Playwright install -- awk によるドライランを使用して、Playwright が Chrome ブラウザを検索するルート フォルダーを決定します。これを CHROMIUM_PATH 変数の値として設定します。
CHROMIUM_PATH/chrome-linux に新しいフォルダー (および必要な親フォルダー) を作成します。これは、Playwright が Chrome バイナリを検索する実際のフォルダーです。
Chrome が Chrome の Heroku ビルドパック インストール (/app/.chrome-for-testing/chrome-linux64/chrome) を指すように、そのフォルダーにシンボリックリンクを作成します。
更新された app.json ファイルを使用すると、Playwright はビルドパックからの Chrome インストールを使用できるようになります。もう一度テストを実行する時が来ました。
成功!
テストセットアップ スクリプトは期待どおりに実行されました。
Playwright は Chrome バイナリにアクセスしてテストを実行でき、テストは成功しました。
Web アプリケーションのエンドツーエンドのテストは煩雑ではなくなってきているので、ますます優先順位を上げています。最近では、Playwright の使用も増えています。柔軟かつ高速です。 Heroku CI の Chrome for Testing ビルドパックを立ち上げて実行するための作業 (私 と皆さん !) が完了したので、ブラウザ自動テスト スイートの構築を一度開始できます。またまた。
このチュートリアルのコードは、私の GitHub リポジトリから入手できます。
コーディングを楽しんでください!
以上がHeroku での Playwright と Chrome ブラウザのテストの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。