E2Eテストって何?
E2E(End-to-End)テストとは、アプリケーションの動作を実際のユーザーの視点から検証するテスト手法です。ユーザーがアプリケーションを使用する際の一連のフローを自動化 して、システム全体が期待通りに動作するかを確認します。
フロントエンドからバックエンド、データベースまで含めた統合テストの実行が可能であり、システム全体の品質保証に重要な役割を果たします。
Playwrightって何?
Playwrightは、Microsoft社が開発した最新のE2Eテストフレームワーク です。ウェブブラウザを自動操作してテストを行うためのツールで、主な特徴は:
- 複数ブラウザ対応: Chrome、Firefox、Safari、Edge などの主要なブラウザで同じテストコードが動作
- 自動待機機能: ページの読み込みやAPI通信などを自動で待機し、テストの安定性が向上
- 強力なセレクター: 高度なCSSセレクターやテキスト検索によるDOM要素の特定
- モバイルエミュレーション: モバイルデバイスの挙動をエミュレート可能
- ネットワークインターセプト: APIリクエストのモックやネットワークトラフィックの監視
- 並列実行: 複数のブラウザやシナリオを並列実行可能
Cypress、Selenium、Puppeteerなどの他のツールと比較して、より堅牢で高速、そして使いやすいAPIを提供しています。
PlayWrightの導入方法
必要なもの・前提条件
- Node.js: バージョン14以上推奨
- NPM: パッケージマネージャー
- テスト対象のウェブアプリケーション: ローカルまたは公開されているサイト
- コードエディタ: VS Code、WebStorm、Cursor など、VSCodeがフォークされたエディタであれば使用可能
Node.jsが入っていない場合
% brew install nodejs
npmが入っていない場合
% brew install npm
1. E2Eテストを実行するためのディレクトリを用意
% mkdir playwright-demo && cd playwright-demo
2. VSCodeにPlaywrightの拡張機能をインストール
以下の拡張機能をインストールします。
3. VSCodeのコマンドパレットを使用してPlaywrightをインストール
キーボードで「Command + Shift + p」を押下すると、以下のようにコマンドを実行できる「コマンドパレット」が開きます。
ここで、「Install Playwright」と入力すると、以下のように「**Test: Install Playwright」というものが出てくるので、クリックします。
すると、「どのブラウザで使用するのか」「JavaScriptで使用するか」「Github Actionsは使用するか」という設定項目が表示されるので、選択して「OK」をクリックします。
すると、インストールが始まるはずです。ターミナルでゴニョゴニョ動き始めたら実行されています。
4. インストールされていることを確認
現在のディレクトリに以下のようにディレクトリとファイルが存在していればOKです。(node_modules
ディレクトリは中身が多すぎるので、省略しています。)
% tree -I node_modules
.
├── package-lock.json
├── package.json
├── playwright.config.ts
├── tests
│ └── example.spec.ts
└── tests-examples
└── demo-todo-app.spec.ts
5. テストファイルを編集する
実行するテストファイルは、tests
ディレクトリに保存をしておきます。
今回はtests
ディレクトリにdemo-example.spec.ts
ファイルを作成してテストを作っていきます。例として、Qiitaのトップページに対するチェックをしていきます。
import { test, expect } from '@playwright/test';
test('has title', async ({ page }) => {
// QiitaサイトへGO
await page.goto('https://qiita.com/');
// タイトルに「Qiita」という文字列が含まれていることを確認
await expect(page).toHaveTitle(/Qiita/);
});
6. テストタブを開く
VSCodeの三角フラスコのマークをクリックすると、テストを実行することのできる画面が表示されます。
これで準備完了です。
PlayWrightの実行方法
上記の画面で、demo-example.spec.ts
にカーソルを当てると、再生ボタンが表示されるのでそれをクリックします。
実行が正常に完了すると、緑色でチェックマークがつきます。
また、ターミナルの「テスト結果」のタブを見ると、「1 passed」という文字が表示されています。
上記のように、テストコードを書いていくことで、E2Eテストを完成させることができます。
テストコードを自動生成する
新しくテストファイルを生成して自動作成する
テストタブを開いている状態で、画面左下の「Record new」をクリックします。
すると、新たにファイルが生成されて「// Recording...」というコメントアウトが表示され、録画用ブラウザが表示されます。
以下の動画のように録画中に画面を操作することで、自動コーディングができます。
限定公開にしちゃっているので、iframe埋め込みができなかったです...
すると、新しくtests/test-1.spec.ts
というようなファイルが作成され、以下のように自動コーディングがされます。
import { test, expect } from '@playwright/test';
test('test', async ({ page }) => {
await page.goto('https://qiita.com/');
await page.getByRole('searchbox', { name: 'Search' }).click();
await page.getByRole('searchbox', { name: 'Search' }).fill('aws');
await page.getByRole('searchbox', { name: 'Search' }).press('Enter');
await page.getByRole('searchbox', { name: 'Search' }).click();
await page.getByRole('searchbox', { name: 'Search' }).fill('python');
await page.getByRole('searchbox', { name: 'Search' }).press('Enter');
await page.getByRole('link', { name: 'Qiita', exact: true }).click();
});
ファイルを保存して、上記と同じようにテストを実行することができます。
既存のテストファイル内でテストコードを生成する
テストタブを開いている状態で、画面左下の「Record at cursor」をクリックします。
すると、録画用ブラウザが開くので、先ほどと同様に操作をします。
途中からコード生成を始める場合でも「about blank」状態のブラウザが開きますので、自分で操作してテストコードを生成したいページまで操作する必要があります。この時に操作したテストコードも生成されてしまいますので、不要であれば手動で削除しましょう。
ちょっとだけ工夫(誰でも思いつきそう)
環境によってurlやログインユーザをセットする
どのアプリケーションも「検証環境」「ステージング環境」「本番環境」が用意されているものと思います。
テスト実行時に、どの環境でテストを実行するかを指定するだけでアクセスするURLやログインユーザを用意できるようにしておくと、テスト実行する時の考慮が減ります。
let env = 'stg' // dev or stg or pro
if (env === 'dev') {
var url = 'https://dev.example.com'
var user_name = 'dev_testuser_01'
var password = 'dev_testuser_01'
} else if (env === 'stg') {
var url = 'https://stg.example.com'
var user_name = 'stg_testuser_01'
var password = 'stg_testuser_01'
} else if (env === 'pro') {
var url = 'https://pro.example.com'
var user_name = 'pro_testuser_01'
var password = 'pro_testuser_01'
}
test('Lets Test!!', async ({ page }) => {
await page.goto(`${url}/users/sign_in`);
await page.getByRole('textbox', { name: 'ユーザID' }).fill(user_name);
await page.getByRole('textbox', { name: 'パスワード' }).fill(password);
await page.getByRole('button', { name: 'ログイン' }).click();
...
end
繰り返し実行された時に同じ名前のデータが生成されないようにする
Playwrightでは、1つのページに同じ文字列を持つ要素が複数存在している場合、エラーが発生してしまいます。そのため、登録するデータが一意であるととても良いです。(個人的な感想)
世の中に存在する一意の文字列といえば?
...
タイムスタンプ!
自分は、「マイルストーン」と「タイムスタンプ」を組み合わせてテストデータを生成しています。
// バージョンを指定
const version = 'v2.6.4'
// タイムスタンプを生成
const now: Date = new Date();
const hours: string = now.getHours().toString().padStart(2, '0');
const minutes: string = now.getMinutes().toString().padStart(2, '0');
const seconds: string = now.getSeconds().toString().padStart(2, '0');
const formattedTime: string = `${hours}${minutes}${seconds}`;
// テストデータを生成
const customer_name = `試験用顧客_${version}_${formattedTime}`
const device_serial = `device_for_test_${version}_${formattedTime}`
test('Lets Test!!', async ({ page }) => {
...
// 一覧画面へ
await page.getByRole('link', { name: ' 顧客' }).click();
// 新規登録画面へ
await page.getByRole('link', { name: '新規登録' }).click();
await expect(page.locator('h1 small', { hasText: '新規登録' })).toBeVisible();
// 入力
await page.locator('#customer_name').fill(customer_name);
await page.getByRole('textbox', { name: '備考' }).fill('テストだよ!');
await page.getByRole('button', { name: '登録' }).click();
await page.waitForURL('**/customers/*');
// 閲覧画面に遷移していることの確認
await expect(page.locator('h1 small', { hasText: '閲覧' })).toBeVisible();
// 編集
await page.getByRole('button', { name: '編集' }).click();
await expect(page.locator('h1 small', { hasText: '編集' })).toBeVisible();
// 入力
await page.locator('#customer_name').fill(`${customer_name}_update`);
await page.getByRole('textbox', { name: '備考' }).fill('テストだよ!_update');
await page.getByRole('button', { name: '更新' }).click();
...
end
上記のように、要所要所で変数展開を使用しています。
まとめ
今回は弊社の試験やリリース後確認手順にて、Playwrightを使ったE2Eテストを使用し始めたので、その導入方法と使用方法をまとめてみました。
Playwright MCPも公開されているようなので、時間があるときに使用してみたいと思います。
以上