EY-Office ブログ

久しぶりにPlaywrightを使ったら、とても使いやすくなっていた

E2Eテストで良く使われるツールPlaywrightを2年半ぶりに使ったら、とても使いやすいツールになっていました! 🎭

Playwright Bing Image Creatorが生成した画像を元にしています

Playwrigthを使ったE2Eテストの例

いつものReactで書かれたジャンケン・アプリのE2EテストをPlaywrigthを使って書いてみました。

コードの説明は省略しますが、かなりシンプルだと思います。インストールも npm install -save-dev @playwright/test と設定ファイルを1つ書くだけで済みます。

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

test.describe("pages/index.tsx", () => {

  test.beforeEach(async ({page}) => {
    await page.goto('http://localhost:3000');
  });

  test("アクセスすると「じゃんけん ポン!」と表示されている", async ({page}) => {
    await expect(page.getByRole("heading")).toContainText(/じゃんけん ポン!/);
  });

  test("グーをクリックすると対戦が行われ、対戦結果が表示される", async ({page}) => {
    await page.getByRole("button", { name: "グー" }).click();

    const [_time, human, computer, judgment] = await page.getByRole("cell")
        .allTextContents();

    expect(human).toBe("グー");
    expect(computer).toMatch(/^(グー|チョキ|パー)$/);
    expect(judgment).toMatch(/^(勝ち|引き分け|負け)$/);
  });

  test("グーをクリックした後に対戦成績をクリックすると、対戦成績が表示される", 
      async ({page}) => {
    await page.getByRole("button", { name: "グー" }).click();
    await page.getByText("対戦成績").click();

    const [win, lose, draw] = await page.getByRole("row").allTextContents();

    expect(win).toMatch(/勝ち[01]/);
    expect(lose).toMatch(/負け[01]/);
    expect(draw).toMatch(/引き分け[01]/);
  });

  test("2回クリックすると、対戦結果が2行表示される", async ({page}) => {
    await page.getByRole("button", { name: "グー" }).click();
    await page.getByRole("button", { name: "グー" }).click();

    const scores = await page.getByRole("row").filter({hasNotText: /時間/})
        .allTextContents();
    expect(scores.length).toBe(2)
  })

});

アサーション(Assertions)機能が含まれるようになった

初期のPlaywrightは画面なしのブラウザー機能を実現したもので、クリックや文字入力のような操作や、ブラウザーに表示されている文字等を確認する機能のみを持ったツールでした。E2Eテストを書くにはJest等のテスティング・フレームワークと組み合わせる必要がありましたが、現在はアサーション機能が含まれ、他のテスティング・フレームワークが不要になりました。

const text = await page.$eval("h1", (e: Element) => e.textContent);
expect(text).toMatch(/じゃんけん ポン!/);

初期版では上のようにPlaywrightで画面上の表示文字列をJSの文字列として取得し、Jestのアサーションに渡す形になっていました。しかし、現在は下のように専用のアサーションがあるのでテストがすっきり書けるようになりました。

await expect(page.getByRole("heading")).toContainText(/じゃんけん ポン!/);

また、getByText(), getByRole()などのTesting Libraryと同じような問合せAPIが追加されたのも良いですね。

test()の引数にpageオブジェクトがある

初期版では、ブラウザーの起動、ページの取得などの初期コードが必要でpageオブジェクトを自前で準備していました。

let browser: Browser;
let page: Page;

beforeAll(async () => {
  browser = await playwright['chromium'].launch({headless: true});
  const context = await browser.newContext();
  page = await context.newPage();
});

しかし、現在は下のテストコードのように、test()の引数pageを使う事で直ぐにテストが書けます。

test("アクセスすると「じゃんけん ポン!」と表示されている", async ({page}) => {
  await expect(page.getByRole("heading")).toContainText(/じゃんけん ポン!/);
});

サーバーの自動起動もできる

現在のPlaywrightの設定ファイル playwright.config.ts に以下のようにwebServer項目でアプリを動かすサーバーの自動起動も出来ます!

import type { PlaywrightTestConfig } from "@playwright/test";
import { devices } from "@playwright/test";

const baseURL = "http://localhost:3000";

const config: PlaywrightTestConfig = {
  testDir: "./e2e",
  webServer: {
    command: "npm run dev",
    url: baseURL,
    timeout: 120 * 1000,
    reuseExistingServer: !process.env.CI,
  },
  use: {
    baseURL,
  },
  projects: [
    {
      name: 'Desktop Chrome',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
};

export default config;

また、projects:に複数の(サポートしている)ブラウザーを追加することで、複数のブラウザーでテストを実行できます。

まとめ

今回は説明出来ませんでしたが、UI Modeでインタラクティブにテストを実行したり、VS Codeと連携したり、人間が行ったブラウザー操作を記録してテストコードを生成する機能もあるようです。→ Test generator

結論として、Playwrightは高機能で使いやすいE2Eテストツールです。 🎭

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ