HEARTBEATS

VS CodeとPlaywrightを使ったE2Eテストの実施

   

技術開発チーム・運用技術開発担当(通称opdev)の辰已です。

opdevは社内のさまざまなプロダクトの開発・保守運用を行っており、日々業務効率改善、ハートビーツの価値向上に繋がる技術開発・情報発信を行っています。

先日、opdevで開発した社内向けのプロダクトに対して、Visual Studio Code(以下VS Code)Playwrightを使ってE2Eテストを実施しました。 セットアップが簡単で、使い勝手も良かったので、今回はVS CodeとPlaywrightを使ったE2Eテストの実施方法を紹介します。

Playwrightとは

PlaywrightはE2Eテストやブラウザ自動操作用のフレームワークで、Microsoftがオープンソースで開発をしています。 他によく使われるE2Eテストフレームワークには、Selenium、Puppeteer、Cypressがあります。npmパッケージのダウンロード数の推移を確認できるnpm trendを見ると、Playwrightは2024年5月中頃に首位だったCypressを追い越し、パッケージのダウンロード数がトップになっています。

Playwrightの特徴は以下の通りです。

  • Any browser • Any platform • One API
    クロスブラウザ、クロスプラットフォーム、複数言語で利用可能
  • Resilient • No flaky tests
    自動ウェイトによりタイミングの調整が不要
  • No trade-offs • No limits(※1)
    複数ブラウザ、タブにも対応
  • Full isolation • Fast exec
    高速な実行、認証状態保持による繰り返しログインの排除
  • Powerful Tooling
    テストコード生成のための操作記録、テスト失敗時のさまざまな解析ツール群

Playwrightは後発のフレームワークであり、他のテストフレームワークの課題を改善している点が大きな特徴です。

※1. おそらくtrade-offsの単語はCypressのTrade-offsを意識しているのでしょう。

Playwrightの導入

実際にVS CodeにPlaywrightを導入してみましょう。 MicrosoftはPlaywrightだけでなく、VS Code向けのPlaywright拡張機能も提供してくれています。周辺環境まで整備してくれているのは嬉しいですね。 なお、VS Codeの操作方法については本筋から外れるため割愛します。

  • 拡張機能をインストールする
    VS CodeでPlaywright Test for VSCodeを検索し、 installボタンをクリックして拡張機能をインストールします。 拡張機能
  • プロジェクトを開く
    テスト用プロジェクトを作成するディレクトリを開いておきます。今回はディレクトリ名をplaywright_sampleという名前で作成しました。 プロジェクトを開く
  • Playwrightのインストール
    コマンドパレットからtest: Install Playwrightを選択してPlaywrightをインストールします。
    Playwrightのインストール
    選択肢はそのままで問題ありません。Firefox不要、WebKit不要などがあれば適宜変更してください。 Playwrightインストール時の選択

これだけで環境構築が完了です。とても簡単ですね!

動作確認

実際にPlaywrightを動かしてみましょう。実行対象のテストコードはtestsディレクトリ以下(※2)のファイルになります。 VS Codeのアクティブバーからテストエクスプローラーを開き、実行したいテスト名の横にある再生マークをクリックしてください。テスト結果がTest Resultターミナルに表示されたらOKです。
テスト実行

また、デバッガーを起動したい場合は、実行したいテスト名の横にある虫付き再生マークをクリックしてください。
デバッグ実行

これだけでデバッガーが使えます!launch.jsonの作成・パスの調整など、いろいろな設定をすることなくデバッグ環境まで構築できるのはとても嬉しいですね。

※2. playwright.config.tstestDirにデフォルトで./testsが指定されているためです。

テストへの適用

実際にフロントエンドとバックエンドを分離した構成のアプリケーションをテストしてみましょう。 テスト対象のサンプルシステムは以前のブログにて作成したものがあるため、それを利用します。

サンプルシステムの構成は以下のようになっています。

種類 URL 備考
バックエンド http://127.0.0.1:8081 /item のエンドポイントでアイテムの情報を返す
フロントエンド http://127.0.0.1:8080 バックエンドの/itemエンドポイントで取得したデータをブラウザに表示する

サンプルシステムの起動方法は以下の各リポジトリのREADMEを参照してください。

レコード機能を使ってテストコードを作成する

ゼロからテストコードを手で書くことも可能ですが、非常に手間がかかってしまうためオススメできません。Playwrightのレコード機能を利用しましょう。 レコード機能は、ブラウザでの操作を記録してくれる機能です。実施したいテストを画面上で操作するだけで、Playwrightが自動的に操作に対応するテストコードを作成してくれます。 以下で表示の確認、表示文字列の確認、設定値の確認を行うテストの例を作成します。

  • 記録の開始
    VS Codeのアクティブバーからテストエクスプローラーを開き、PlaywrightのアコーディオンからRecord newを選択してブラウザを起動します。
    記録の開始

  • テスト対象のページにアクセス
    表示されたブラウザのURLに127.0.0.1:8080を入力してフロントエンドにアクセスします。
    テスト対象のページにアクセス

  • ブラウザにopenapi_front_sampleが表示されていることを確認するテストの作成

    ブラウザ上部中央のパレットからAssert visibilityを選択し、表示確認対象の要素を選択します。
    AssertVisibility選択

    選択し終えるとテストコードが追加されます。
    AssertVisibilityテストコード追加

  • ブラウザに想定した文字列が正しく表示されているかを確認するテストの作成

    ブラウザ上部中央のパレットからAssert textを選択し、比較対象の要素を選択します。 AssertText選択

    比較対象に表示される想定の文字列を設定します。
    AssertText文字列設定

    設定し終えるとテストコードが追加されます。
    AssertTextテストコード追加

  • ブラウザに想定したInputの値が正しく設定されているかを確認するテストの作成

    ブラウザ上部中央のパレットからAssert valueを選択し、比較対象の要素を選択します。
    AssertValue選択

    選択し終えるとテストコードが追加されます。必要な場合は適宜値を設定してください。
    AssertValueテストコード追加

  • 記録の終了
    ブラウザ上部中央のパレットからRecordの赤丸をクリックします。

上記操作後、tests/test-1.spec.tsには以下のようなテストコードが生成されます。

import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.goto('http://127.0.0.1:8080/');
  await expect(page.getByRole('heading', { name: 'openapi_front_sample' })).toBeVisible();
  await expect(page.getByRole('main')).toContainText('{"name":"test","description":"description","price":10,"tax":1}');
  await expect(page.getByRole('textbox')).toHaveValue('10');
});

もちろん、このテストコードを手で修正することも可能です。 とりあえずレコード機能を使ってざっくりテストを作り、細かな修正は後ほど手で直す、とすれば毎回DOMを調べなくても良いので、効率よくテストコードが作成できます。

レスポンスをモックしてみる

E2Eテストでは他システムも含め、できる限り本番と同じ環境でテストを行うことが理想です。しかし、実際にデータが書き込まれてしまうと困る、意図的にエラーを発生させることが難しい場合など、どうしてもモックを利用せざるを得ないケースもあります。そのようなときに便利なのがfulfillです。fulfillは、指定したURLのレスポンスをモックする関数です。Playwrightにデフォルトで含まれている関数なので、追加のパッケージをインストールする必要はありません。

試しに、APIサーバーのレスポンスをmock-dataに変更して実行してみましょう。

import { test, expect } from '@playwright/test';

test('test', async ({ page }) => {
  await page.route('http://127.0.0.1:8081/item', async (route) =>{await route.fulfill({json:'mock-data'})}); // この1行を追加

  await page.goto('http://127.0.0.1:8080/');
  await expect(page.getByRole('heading', { name: 'openapi_front_sample' })).toBeVisible();
  await expect(page.getByRole('main')).toContainText('{"name":"test","description":"description","price":10,"tax":1}');
  await expect(page.getByRole('textbox')).toHaveValue('10');
});

APIサーバーのitemエンドポイントのレスポンスをmock-dataに書き換えました。URLを指定し、そのレスポンスを定義するだけです。 この状態で、先ほどのテストを実行してみましょう。

Error: expect(locator).toContainText(expected)


Locator: getByRole('main')
Expected string: "{\"name\":\"test\",\"description\":\"description\",\"price\":10,\"tax\":1}"
Received string: "\"mock-data\""

以前はパスしていたテストがエラーになります。 Expectedが変更前のAPIのJSONになっていますが、Receivedはmock-dataになっています。APIサーバーのレスポンスを上書きできていますね。

Playwrightには他にもさまざまな便利な機能があります。興味がある方は公式ドキュメントをご覧ください。

おわりに

本記事では、VS CodeとPlaywrightを使ったE2Eテストの実施方法を紹介しました。他にもさまざまなテスト用関数や、アクション機能などがありますが、今回はグラフィカルに操作可能な部分に焦点を当てて紹介してみました。 簡単な例でしたが、少しでも参考になれば幸いです。

株式会社ハートビーツの技術情報やイベント情報などをお届けする公式ブログです。



ハートビーツをフォロー

  • Twitter:HEARTBEATS
  • Facebook:HEARTBEATS
  • HATENA:HEARTBEATS
  • RSS:HEARTBEATS

殿堂入り記事