E2Eテストフレームワーク Playwright の始め方


Playwright とは

Selenium ・ Selenide ・ Cypress などと同様な E2E テストツールで、MS により OSS として開発されています。

以下のように紹介されています。

Playwright は、Webテスト/自動化のためのフレームワークです。 単一の API で Chromium、Firefox および WebKit をテストできます。 Playwright は、クロスブラウザーのWebオートメーションを 安定に、機能的で、信頼性が高く、高速に実現できるよう構築されています。

github.com

ブラウザでのテストで問題になるレスポンスの待機についても、Auto-waitingに記載の自動待機により安定したテストが実現できます。

現在であれば、Cypress か Playwright の何れかを選択することになるでしょう。

ここでは、Playwright の使い方について簡単に見ていきます。


インストール

Playwright は npm パッケージとして提供されています。

そのためインストールは以下のようになります。

$ npm init playwright@latest

yarn の場合は yarn create playwright、pnpm の場合は pnpm dlx create-playwright となります。

インストール時には以下のオプション選択が選べます。

✔ Do you want to use TypeScript or JavaScript? · TypeScript
✔ 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 'npx playwright install')? (Y/n) · true
  • TypeScript と JavaScript のいずれを利用するか
  • テスト用のディレクトリ名
  • GitHub Action のワークフローを追加するかどうか
  • Playwright が利用するブラウザのインストールを行うかどうか

Playwright が利用するブラウザは、以下にキャッシュとしてインストールされます。

  • Windows の場合は %USERPROFILE%\AppData\Local\ms-playwright
  • MacOS の場合は ~/Library/Caches/ms-playwright
  • Linux の場合 ~/.cache/ms-playwright

サイズが大きいので、初回はそれなりにダウンロード時間がかかります。


インストールは以下の出力とともに完了します。

Inside that directory, you can run several commands:

  npx playwright test
    Runs the end-to-end tests.

  npx playwright test --project=chromium
    Runs the tests only on Desktop Chrome.

  npx playwright test example
    Runs the tests in a specific file.

  npx playwright test --debug
    Runs the tests in debug mode.

  npx playwright codegen
    Auto generate tests with Codegen.

We suggest that you begin by typing:

    npx playwright test

And check out the following files:
  - .\tests\example.spec.ts - Example end-to-end test
  - .\tests-examples\demo-todo-app.spec.ts - Demo Todo App end-to-end tests
  - .\playwright.config.ts - Playwright Test configuration

Visit https://playwright.dev/docs/intro for more information. ✨

Happy hacking! 🎭

以下のファイルが作成されます。

  • playwright.config.ts : Playwrightの各種設定
  • tests/example.spec.ts : Playwrightテストのひな形
  • tests-examples/demo-todo-app.spec.ts : テストサンプル

大抵の場合は、tests 配下に E2E テストの仕様を記載していくことになるでしょう。


テストの実行

ひな形として作成された example.spec.ts は以下のようになっています。

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

test('homepage has title and links to intro page', async ({ page }) => {
  await page.goto('https://playwright.dev/');

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);

  // create a locator
  const getStarted = page.getByRole('link', { name: 'Get started' });

  // Expect an attribute "to be strictly equal" to the value.
  await expect(getStarted).toHaveAttribute('href', '/docs/intro');

  // Click the get started link.
  await getStarted.click();

  // Expects the URL to contain intro.
  await expect(page).toHaveURL(/.*intro/);
});

テストは以下のように実行します。

$ npx playwright test example.spec.ts

デフォルトでは、ヘッドレスモードで chromium、firefox、webkit を使ったテストが並列で実行されます(playwright.config.ts にて設定を変更できます)。

単に全てのテストを実行するには以下のようにするだけです。

$ npx playwright test

以下のようにすることで、ヘッドモードで chromium だけを指定してテストできます。

$ npx playwright test example.spec.ts --headed --project=chromium


テスト結果は以下でレポート形式で確認できます。

$ npx playwright show-report

テストはデバッグモードで実行することで、ステップ実行しながらセレクタ内容の確認などを行うことができます。

$ npx playwright test example.spec.ts --debug --project=chromium


テストの宣言

Playwright では、test(title, testFunction) 関数によりテストを宣言します。

test('basic test', async ({ page }) => {
  // ...
});

このテストはテストフィクスチャとして、分離されたコンテキストで実行されます。 単一のブラウザーで複数のテストを実行する場合でも、すべてのテストが独立した環境として実行されるため、安定したテストが可能となっています。

以下のようにテストをグルーピングすることもできます。

test.describe('two tests', () => {
  test('one', async ({ page }) => {
    // ...
  });

  test('two', async ({ page }) => {
    // ...
  });
});

テストの前後に処理を行うテストフックを定義することもできます。

test.beforeAll(async () => {
  console.log('Before tests');
});

test.afterAll(async () => {
  console.log('After tests');
});

test('my test', async ({ page }) => {
  // ...
});

それぞれのテストの前後に処理をフックする場合は以下のようになります。

test.beforeEach(async ({ page }, testInfo) => {
  console.log(`Running ${testInfo.title}`);
  await page.goto('https://my.start.url/');
});

test.afterEach(async ({ page }, testInfo) => {
  console.log(`Finished ${testInfo.title} with status ${testInfo.status}`);

  if (testInfo.status !== testInfo.expectedStatus)
    console.log(`Did not run as expected, ended up at ${page.url()}`);
});


テストフィクスチャ

テストは以下のように test(title, testFunction) 関数に記載することは先に述べました。

test('basic test', async ({ page }) => {
  await page.goto('https://playwright.dev/');
  // ...
});

testFunction の引数のとなっている { page } はテストフィクスチャとしてフレームワークにより提供されます。

この場合はテストごとの分離された Pageインスタンス で、テストで使用される最も一般的なフィクスチャとなります(Page は、 Browserの単一のタブを表します)。

この Pageインスタンスを介して各種のページ操作を行えます。代表的なものは以下となります。

  • page.goto(url[, options]):指定URLへの遷移
  • page.goBack([options]):ヒストリーバック
  • page.goForward([options]):ヒストリーフォワード
  • page.reload():現在のページを再読み込み
  • page.waitForFunction(pageFunction[, arg, options]):pageFunction を満たすまで待機
  • page.screenshot([options]):スクリーンショットの取得


Locators

画面の要素を操作は Page インスタンスから取得した Locator により行います。

ロケータは、Playwright の自動待機および再試行機能の中心的な部分になります。

ロケーターは、ページ上の要素をいつでも見つける方法を表し、.click .fill などの要素に対してアクションを実行するために使用します。

Locator 取得の代表的な関数は以下のようなものがあります。

  • page.locator('.todo-list li .toggle')
  • page.getByRole('button', { name: 'Clear completed' })
  • page.getByLabel('Mark all as complete')
  • page.getByPlaceholder('What needs to be done?')
  • page.getByText(text[, options])
  • page.getByTestId('todo-title')

page.getByTestId() は、data-testid 属性に定義されたものを ID として検索する関数です。

その他は、関数名から想像の通りのセレクタとして機能します。

詳細は Pageクラス のAPIリファレンスを参照してください。


取得したロケータに対して、以下のような操作を行うことができます。

  // create a locator
  const getStarted = page.getByRole('link', { name: 'Get started' });

  // Click the get started link.
  await getStarted.click();

代表的なものには以下があります。

  • locator.check([options])
  • locator.click([options])
  • locator.dblclick([options])
  • locator.fill(value[, options])
  • locator.press(key[, options])

fill<input><textarea> への入力を意味します。

詳細は Locatorクラス のAPIリファレンスを参照してください。


アサーション

Playwright Test では、Jest の expect を拡張したアサーションが提供されています。

拡張されたアサーションは、予想する条件が満たされるまで待機する非同期マッチャーとなっています。

取得したロケータやページに対して、以下のようなアサーションを行うことができます。

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);

  // create a locator
  const getStarted = page.getByRole('link', { name: 'Get started' });

  // Expect an attribute "to be strictly equal" to the value.
  await expect(getStarted).toHaveAttribute('href', '/docs/intro');

代表的なものには以下があります。

  • expect(page).toHaveTitle(titleOrRegExp[, options])
  • expect(locator).toHaveText(expected[, options])
  • expect(locator).toContainText(expected[, options])
  • expect(locator).toHaveClass(expected[, options])
  • expect(locator).toHaveValue(value[, options])
  • expect(locator).toBeEmpty([options])
  • expect(locator).toBeChecked([options])

詳細は Assertions を参照してください。


テストコードの記録

Playwright にももちろんテストジェネレーター機能があります。

$ npx playwright codegen <url>

codegen を実行すると、ブラウザーウィンドウと、テストの記録などを行う Playwright Inspector ウィンドウが起動します。

ブラウザを操作した内容は Playwright Inspector に記録されるため、この内容をテストコードのひな形として利用することができます。


まとめ

Playwright の簡単な利用方法について紹介しました。

利用者数としては Cypress のがまだまだ多いような気もしますが、個人的には Playwright を強く押したいですね。