E2EテストツールのPlaywrightをさわりながら基本的な機能を知る

Playwrightをさわりながら基本的な機能の紹介をしていきます。PlaywrightはE2Eテストとして人気が高まっているツールです。ぜひ、基本的なコンセプトについて理解を深めてください。

動作確認バージョン

  • @playwright/test: 1.43.1

Playwrightのインストール

npmコマンドでplaywrightをインストールします。

mkdir playwright-test
cd playwright-test

npm init playwright@latest

実行すると、@playwright/testがインストールされ、設定ファイル(playwright.config.ts)、サンプル用のテストファイルが生成されます。また、テスト用のブラウザとして、ChromiumFirefoxWebkitもダウンロードされます。

Playwrightのサンプルのテストを動かしてみる

Playwrightは、ブラウザを操作するためのツールです。Playwrightを使って、ブラウザを操作するテストを書いてみましょう。

サンプルのテストを確認する

tests/example.spec.tsにサンプルのテストが生成されています。このテストは、Playwrightの公式サイトにアクセスし、タイトルがPlaywrightを含むことを確認するテストです。

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

test('has title', async ({ page }) => {
  // https://playwright.dev/ にアクセス
  await page.goto('https://playwright.dev/');

  // titleタグに"Playwright"が含まれていることを確認
  await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
  // https://playwright.dev/ にアクセス
  await page.goto('https://playwright.dev/');

  // "Get started"というリンクをクリックし、ページ遷移する
  await page.getByRole('link', { name: 'Get started' }).click();

  // ページの見出しに"Installation"が表示されていることを検証する
  await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});

サンプルのテストを実行する

npx playwright testコマンドでテストを実行します。Playwrightはデフォルトでヘッドレス(ブラウザを表示しない)でテストを実行します。

npx playwright test

#### その他のテストの実行方法 ###
# 特定のテストファイルやテストケースのみ実行する
npx playwright test example.spec.ts:10

# Headed modeでテストを実行する
# ブラウザを表示してテストを実行するようになる
npx playwright test --headed

# UI Modeでテストを実行する
# UI Modeはブラウザを表示しながらインタラクティブにテストを実行することができる
# Doc: https://playwright.dev/docs/test-ui-mode
npx playwright test --ui

# Debug Modeでテストを実行する
# 1行ずつデバッグしながらテストを実行できる
# また、`await page.pause();`でブレイクポイントを設定できる
# Doc: https://playwright.dev/docs/debug#run-in-debug-mode-1
npx playwright test --debug

サンプルのテスト結果を確認する

テストを実行したら、npx playwright show-reportコマンドでテスト結果のレポートを表示することができます。

npx playwright show-report

デフォルトでは、HTMLでレポートが表示されます。また、ChromiumFirefoxWebkitの3つのブラウザでテストが実行されるので、それぞれのブラウザでのテスト結果も確認できます。

Playwrightのテストコードを書いてテスト作成

ここまでで、Playwrightの基本的なテストの実行方法とテスト結果のレポートの表示方法がわかりました。では、 https://demo.playwright.dev/todomvc/ に対して、コードを書いてテストを作成してみます。

Playwrightのテストの基本構成はシンプルで、次の3つになります。

  1. ロケーターで要素を見つける
  2. アクションでユーザー操作を実行する
  3. マッチャーを使って要素をアサーションする

0. テストファイルを作成する

まずは、テストファイルを作成します。

touch tests/todo-mvc.spec.ts

そして、次のようなテストを書いてみます。

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

// 全てのテストの前に実行される処理
// https://demo.playwright.dev/todomvc にアクセスする
test.beforeEach(async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc');
});

1. ロケーターで要素を見つける

ロケーターは、ページ上の要素を見つけるために使います。ロケーターには、自動で要素が利用可能になるまで待機する機能がついており、E2Eテストの信頼性が高まるので積極的に利用しましょう。

主要なロケーターとしては次のようなものがあります。

// ロール属性で要素を探す
const submitButton = page.getByRole('button', { name: 'Submit' });

// フォーム内のフォームコントロールに関連付いたラベルのインプット要素を探す
const firstNameInput = page.getByLabel('First Name');

// プレースホルダーによってインプット要素を探す
// 関連づいたラベルがないフォームコントロールで利用する
const firstNameInput = page.getByPlaceholder('Input your first name');

// テキストで要素を探す
const helloWorld = page.getByText('Hello, World!');

// alt属性によって要素を探す。主に画像に使う
const beautifulImage = page.getByAltText('A beautiful image');

// data-testid属性の要素を探す
// getByRole()、getByLabel()、getByText()などが使えない場合に使う
const someElement = page.getByTestId('some-test-id');

// より詳細のロケーターは https://playwright.dev/docs/locators を参照ください

E2Eテストはユーザー操作をシミュレートするため、ユーザーが実際に操作する要素を使うことが重要です。そのため、XSSCSS要素ではなく、ユーザー向けの属性の利用を推奨します。また、可能な範囲でtest-idではなくgetByRolegetByTextなどのロケーターを使うことをおすすめします。

// Bad: DOM構造やCSSは変わりやすいのでテストが失敗しやすくなる
page.locator('button.buttonIcon.episode-actions-later');

// Soso: テキストは変わりやすいのでテストが不安定になる
page.getByTestId('submit-button');

// Good: ロールは変わりづらいのでテストが安定する
page.getByRole('button', { name: 'submit' });

では、todo-mvc.spec.tsでロケーターを使って要素を見つけてみましょう。

test.describe('New Todo', () => {
  test('should add todo items', async ({ page }) => {
    // プレースホルダーでインプット要素を探す
    const newTodoInput = page.getByPlaceholder('What needs to be done?');
  });
});

2. アクションでユーザー操作を実行する

次に、ロケーターで見つけたHTML要素に対してアクションで操作を実行します。よく使うアクションとしては次のようなものがあります。

// goto: 画面遷移
await page.goto('https://playwright.dev/');

// click : クリック操作
const getStartedButton = page.getByRole('link', { name: 'Get Started' });
await getStartedButton.click();

// fill : テキスト入力
await page.getByRole('textbox').fill('Peter');
await page.getByLabel('Birth day').fill('2020-02-02');

// check : チェックボックスにチェックをつける
await page.getByLabel('I agree to the terms above').check();

// selectOption : セレクトボックスにチェックをつける
await page.getByLabel('Choose a color').selectOption('blue');
await page.getByLabel('Choose multiple colors').selectOption(['red', 'green', 'blue']);

// press : キーボード操作
await page.getByText('Submit').press('Enter');
await page.getByRole('textbox').press('Control+ArrowRight');

// その他のアクションは、 https://playwright.dev/docs/input を参照ください

では、todo-mvc.spec.tsでアクションを使ってTODO項目を入力して、Enterキーを押してみましょう。

test.describe('New Todo', () => {
  test('should add todo items', async ({ page }) => {
    // プレースホルダーでインプット要素を探す
    const newTodoInput = page.getByPlaceholder('What needs to be done?');

    // テキスト入力
    await newTodoInput.fill('寝る前に歯を磨く');
    // Enterキーを押す
    await newTodoInput.press('Enter');
  });
});

3. マッチャーを使って要素をアサーションする

では、expectとマッチャーを使って要素のアサーション(検証)を行います。いくつかのアサーションはパスするかタイムアウトまで自動でリトライする機能があります。

// 一般的なアサーション
// Doc: https://playwright.dev/docs/api/class-genericassertions
// toBeTruthy : 真偽値がtrueか
const success = true;
expect(success).toBeTruthy();
// toEqual : オブジェクトのプロパティが一致するか
const value = { prop: 1 };
expect(value).toEqual({ prop: 1 });

// Pageのアサーション
// Doc: https://playwright.dev/docs/api/class-pageassertions
// toHaveTitle : タイトルが一致するか
await expect(page).toHaveTitle(/Playwright/);
// toHaveURL : URLが一致するか
await expect(page).toHaveURL('https://playwright.dev/');

// ロケーターのアサーション
// Doc: https://playwright.dev/docs/api/class-locatorassertions
// toBeChecked : チェックボックスがチェックされているか
await expect(locator).toBeChecked();
// toBeEnabled : 要素が有効か
await expect(locator).toBeEnabled();
// toBeVisible : 要素が表示されているか
await expect(locator).toBeVisible();
// toHaveAttribute : 要素が指定した属性を持っているか
await expect(locator).toHaveAttribute();
// toHaveText : 要素内の子要素も含むテキストが一致するか
await expect(locator).toHaveText(/Hello/);
// toHaveValue : 要素のValue属性の値が一致するか
await expect(locator).toHaveValue(/[0-9]/);

では、todo-mvc.spec.tsで入力したTODO項目が表示されているか検証します。

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

// 全てのテストの前に実行される処理
// https://demo.playwright.dev/todomvc にアクセスする
test.beforeEach(async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc');
});

test.describe('New Todo', () => {
  test('should add todo items', async ({ page }) => {
    // プレースホルダーでインプット要素を探す
    const newTodoInput = page.getByPlaceholder('What needs to be done?');

    // テキスト入力
    await newTodoInput.fill('寝る前に歯を磨く');

    // Enterキーを押す
    await newTodoInput.press('Enter');

    // 入力したTODOのテキストが表示されているか確認
    await expect(page.getByTestId('todo-title')).toHaveText([
      '寝る前に歯を磨く',
    ]);
  });
});

では、最後にテストを実行してPASSすることを確認します。

$ npx playwright test tests/todo-mvc.spec.ts

Running 3 tests using 3 workers
  3 passed (3.6s)

To open last HTML report run:

  npx playwright show-report

PlaywrightのCodegen機能でブラウザ操作からテスト作成

Playwrightには、ブラウザ操作を記録してテストコードを生成するCodegenという機能があります。これを使うと、ブラウザ操作からPlaywrightのテストコードを簡単に作成することができます。

1. Codegenを起動する

まず、npx playwright codegenCodegenを起動します。起動すると、ブラウザ操作をレコーディングするためのウィンドウとテストコードのウインドウ(Inspector)の2つのウインドウが表示されます。

npx playwright codegen

補足:レコーディングのウインドウの上部にあるアイコンは左から、「レコーディング実施・停止」「ロケーター」「表示のアサーション」「テキストのアサーション」「Valueアサーション」となっています。

2. ブラウザ操作でテストコードを作成する

では、ブラウザのURLに https://demo.playwright.dev/todomvc/#/ を入力します。すると、自動的にInspectorにgotoメソッドが追加されます。

ブラウザ操作を行いながらテストコードを作成してみましょう。自動でテストコードが生成されていきます。 (@playwright/test: 1.43.1 では日本語を上手く認識できないことがあるかもです)

最後にInspecorのコードをコピーして、テストファイルを作成すれば完成です。

VS CodeのExtensionを使うことでより簡単にPlaywrightのコードを生成することができます。興味がある方は、 https://playwright.dev/docs/codegen の「Generate tests in VS Code」を参照くださいませ。

Playwrightのより詳しい情報