🎭

完全に理解できる!Playwrightことはじめ

2023/02/04に公開

はじめに

本記事では、Playwrightを使ったテスト実装についてざっくりとまとめます。

この記事は誰のためのものか

✔ Playwrightで可能なことを知りたい人
✔ 使い方を忘れてしまった人、及び未来の私

🎭 Playwrightとは

Microsoftが中心となり、OSSとして開発しているWebテスト/自動化のためのフレームワークのことを指します。主にE2Eテストで利用します。

OSS(Open Source Software)とは?

ソースコードが公開されていて、誰でも自由に利用・改変・再配布することができるソフトウェアのことです!OSSは、有志のコミュニティによって開発され、メンテナンスされています。

E2E(End-to-End)テストとは?

アプリケーションの提供機能が、ユーザーの期待通りに動作するかをテストする方法です。
アプリケーションが実際に使用される環境でテストすることを意味します📝

https://github.com/microsoft/playwright

導入

利用したいプロジェクトのターミナルで以下を叩きます。

$ yarn create playwright

この記事ではyarnで進めていきます。
npm pnpmを利用したい方はこちらを参考にしてください!
https://playwright.dev/docs/intro

何が違うの?

npm
Node.jsの既定のパッケージマネージャー。一番利用されているし、使い方が簡単。
記事やパッケージが充実!安心安全🏥
yarn
npmの代替。高速で、さらに安全&&一貫性を持っている。
パッケージの管理方法も効率的で、フォルダのサイズを縮小することができる!
pnpm
さらにさらにインストールが高速。
ディスク使用量💿が優れていることを目的とした新しいパッケージマネージャー!
インストールのパフォーマンスを向上させることができる。
※ 超ざっくり説明。諸説アリ

テスト実装

ブラウザ操作からコードを生成できる codegen

Playwrightには、デフォルトでコードジェネレータが実装されています。これにより、テストコードの実装経験がなくても、ブラウザ操作によって直感的なテストコードの生成が可能となります。(使わなくても問題ないですが、利用する方がテストのイメージが掴みやすいです)

$  yarn playwright codegen [対象URL]
baseURLが存在する場合

以下のように設定しておきましょう!

package.json
 "scripts": {
    "codegen": "playwright codegen '[対象URL]'"
  },
playwright.config.ts
  import type { PlaywrightTestConfig } from "@playwright/test";

const config: PlaywrightTestConfig = {
  use: {
    baseURL: "[対象URL]",
  },
};

export default config;

そうすると、$yarn codegenで実行できるようになります。

上記を実行すると、ブラウザが立ち上がり以下のようにコードを生成してくれます。
コピーして記述したいファイルに貼り付けてください。

生成されたコードは万能ではないため、必ず確認し修正しましょう!

設定する

Playwrightでは、テスト実行の様子を動画やスクリーンショットで残すこともできます。テスト失敗時に、ログを確認できるような設定を追加しておきましょう。(デフォルトはオフ)
また、GitHub Actions上で実行したいのでworkflow設定も行います。

playwright.config.ts
import { PlaywrightTestConfig } from "@playwright/test";

const config: PlaywrightTestConfig = {
  retries: process.env.CI ? 2 : 0, // CI上でリトライしたい回数(今回は2回)
  use: {
    screenshot: "on",
    trace: process.env.CI ? "on-first-retry" : "on", // 初回リトライでトレース
    video: process.env.CI ? "on-first-retry" : "on", // 初回リトライで録画
  },
  reporter: [["html", { outputFolder: "my-report" }]], // 失敗時ブラウザでレポート起動
};
export default config;
.github/workflows/playwright.yml
name: Playwright Tests
on:
  pull_request:
  workflow_dispatch:
  repository_dispatch:
    types: [test]

jobs:
  test:
    runs-on: ubuntu-22.04

    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: "16"
      - name: Install dependencies
        run: yarn

      - name: Run Playwright tests
        run: yarn playwright test

      - uses: actions/upload-artifact@v3
        if: failure() 
        with:
          name: test-results
          path: test-results
          retention-days: 1 # Playwrightのレポートを保存する日数

テスト実行

$ yarn playwright test

実行ログを確認する

テストを実行すると、ターミナル上で結果を確認することができます。

テスト実行に失敗した場合は、ブラウザが立ち上がり詳細を確認することができます。

ブラウザを起動してテスト実行したい場合は、末尾に--headedをつけてください。
(大概実行が早すぎて一瞬で閉じますが...)

デバックモードでの実行も可能です!こちらは末尾に--debugをつけてください。
ブレークポイントを利用した実行が可能となります。指してる場所が分かりやすくなりましたね!

show-traceの活用

show-traceを使うと、動作毎にスクショを撮って後で確認することができます。
これマジでメッチャ良… ネットワークのログまで見れます👀

$ yarn playwright show-report

を叩いてブラウザを確認しましょう。基本はこれで上手くいくはずですが、私はコケました()
ブラウザからzipファイルを選択して開くこともできるので、確認してみましょう!


最高~~~! 実際にここからサンプルを触ることもできます!要チェックです✨

テスト修正

自動生成されたコードは、必ず確認し修正しましょう。(2回目)
…ということで、よく使う実装部分について最低限まとめます!

ページ操作

// 指定URLに遷移
await page.goto(url)
// 再読み込み
await page.reload()
// ページを1つ戻る
await page.goBack()
// ページを1つ進める
await page.goForward()
// pageFunction を満たすまで待機する
await page.waitForFunction(pageFunction)
// 動きを止める(デバック時に利用するかも?)
await page.pause()
// 指定秒待機
await page.waitForTimeout(5000);
// 新しいページを開く
await browser.newPage()

要素の存在を確認

// 要素が存在することを確認
await expect(page.locator("selector")).not.isHidden();
// 要素が存在しないことを確認
await expect(page.locator("selector")).isHidden();
// 要素が表示されていることを確認
await expect(page.locator("selector")).toBeVisible();
// 要素が非表示であることを確認
await expect(page.locator("selector")).not.toBeVisible();

selector指定

// 最初の1つを指定。該当しなければnullを返す
await page.$(selector);
// 複数指定。該当しなければ [] を返す
await page.$$(selector);
// selectorを1つ指定して処理する際に使用
const searchValue = await page.$eval("#search", (el) => el.value);
const preloadHref = await page.$eval("link[rel=preload]", (el) => el.href);
const html = await page.$eval(
  ".main-container",
  (e, suffix) => e.outerHTML + suffix,
  "hello"
);

locator 取得

テスト対象
<div>Hello <span>world</span></div>
<div>Hello</div>
// <span>がマッチ
await page.getByText("world")
// <div>が最初にマッチ
await page.getByText("Hello world")
// 2番目の<div>がマッチ(1番目は半角空白があるため)
await page.getByText("Hello", { exact: true })

// 正規表現も使用可能である、以下はその例
// 両方の<div>にマッチ
await page.getByText(/Hello/)
// 2番目の<div>がマッチ
await page.getByText(/^hello$/i)

ほかにもいっぱいあります!

テスト対象
<form data-testid="mail-form">
  <label for="email">Email:</label>
  <input id="email" type="text" placeholder="Enter your email" >
  <button role="submit" >Submit</button>
</form>
// inputに紐づいたlabelタグのテキストから検索する
await page.getByLabel("email")
// aria-labelを使うときは以下
await page.locator([aria-label=*])
// placeholder属性を利用して検索する
await page.getByPlaceholder("Enter your email")
// role属性を利用して検索する
await page.getByRole("submit")
// data-testid 属性を利用して検索する
await page.getByTestId("mail-form");

// >>と書くとさらに要素を絞れる(=&&)
// 以下はaタグかつテキストがxxであるlocatorを取得します
page.locator("text=xx >> a")

取得したlocatorは以下のように変数の宣言をして利用することが可能です。

const locator = page.getByPlaceholder("name@example.com")
locator.fill("playwright@microsoft.com");

要素の操作

// クリック
page.locator.click()
// ダブルクリック
page.locator.dblclick()
// チェック
page.locator.check()
// 文字入力
page.locator("selector").fill("入力文字"); 
// キー入力
page.keyboard.press("Enter")

ドラッグ&ドロップ

// 操作要素"source"を決める
const source = await page.$("#source");
// 操作要素"target"を決める
const target = await page.$("#target");

// "source"要素を"target"要素にドラッグアンドドロップ
await source.dragAndDrop({
  x: target.boundingBox().x,
  y: target.boundingBox().y
});

アサーション(確認)

Jest の expect を拡張して利用しているらしい[1]🤡

// タイトル確認
expect(page).toHaveTitle("完全に理解できる!Playwrightことはじめ")
// テキスト確認
expect(locator).toHaveText("テキスト確認")
// テキストに含まれているか確認
expect(locator).toContainText("確認")

おわりに

Playwright超初心者だったので、多くの記事を参考にさせていただきました。
この記事が存在しているのは知見を共有してくださった先人たちのおかげです。
この場を借りて御礼申し上げます。

この記事で紹介したのはほんの一例なので、少しでも気になったらこちらもどうぞ!
Playwrightはいいぞ🎭
https://playwright.dev/

参考記事
脚注
  1. Playwright Test uses expect library for test assertions. (docs) ↩︎

Discussion