wheatandcatの開発ブログ

React Nativeで開発しているペペロミア & memoirの技術系記事を投稿してます

PlayWrightを試してみた

TodoアプリにPlayWrightを導入してみたので紹介

PR

github.com

github.com

PlayWrightとは?

playwright.dev

  • 最新のE2Eテストフレームワーク
  • コードジェネレータが使えて便利

モチベーション

以前、記事で紹介した開発中のTODOアプリでmarkdown-to-jsxを使用しているがユニットテストで動かそうとすると正常に動作しない。
なので、E2Eテストで継続的にテストが実装できるか試してみた。

実装

テスト実装は以下のコードジェネレータの機能を使用してベースを作成。

playwright.dev

実行は以下のコマンドで実行

$ yarn playwright codegen  http://127.0.0.1:142

以下みたいに画面が立ち上がり、操作すると自動でテストコードが生成されて簡単にE2Eのテストケースを作成できる。

www.youtube.com

今回作成したいテストケースだと入力した値をlocalStorageに保存しているので、それが正しく保存されているのかテストしたかったので、evaluateの機能を使用。

playwright.dev

evaluateの機能を使用することでE2Eを実行している側のブラウザの情報も取得できるので、ここからlocalStorageを取得して想定通りかチェックしている。

最終的なテストコードは以下のようになった。

e2e/todo.spec.ts

import { test, expect } from "@playwright/test";
// @ts-ignore
import { mockDate } from "./mockdate.ts";
import dayjs from "dayjs";

test.beforeEach(async ({ page }) => {
  await page.goto("/");
});

test("初期画面の確認", async ({ page }) => {
  await expect(page).toHaveTitle(/todo/);
});

test.describe("Markdownの入力テスト", () => {
  test("プレビューにチェックでMarkdownにチェックが付く", async ({ page }) => {
    await page.getByText("編集").click();
    await page.locator("data-testid=input-markdown").click();
    await page
      .locator("data-testid=input-markdown")
      .fill("- [ ] Task1\n- [ ] Task2");
    await page.getByText("プレビュー").click();
    await page.locator("data-testid=checkbox-Task1").click();

    expect(
      await page.locator("data-testid=checkbox-Task1").isChecked()
    ).toBeTruthy();

    await page.getByText("編集").click();

    expect(
      await page.locator("data-testid=input-markdown").inputValue()
    ).toMatch("- [x] Task1\n- [ ] Task2");
  });
});

test.describe("Markdownの入力した時に、保存されるデータのチェック", () => {
  test("編集してチェックした時のデータが保存されている", async ({ page }) => {
    await mockDate(page, "2023-01-01T00:00:00+09:00");

    await page.getByText("編集").click();
    await page.locator("data-testid=input-markdown").click();
    await page
      .locator("data-testid=input-markdown")
      .fill("- [ ] Task1\n- [ ] Task2\n- [ ] Task3");
    await page.getByText("プレビュー").click();
    await page.locator("data-testid=checkbox-Task1").click();

    const taskListValue = await page.evaluate(() => {
      return localStorage.getItem("taskList");
    });

    const r = JSON.parse(taskListValue ?? "").map((task: any) => ({
      ...task,
      checkedAt: task.checkedAt
        ? dayjs(task.checkedAt).format("YYYY-MM-DDTHH:mm:ss")
        : null,
    }));

    expect(r).toMatchObject([
      {
        checked: true,
        checkedAt: "2023-01-01T00:00:00",
        depth: 3,
        text: "Task1",
      },
      {
        checked: false,
        checkedAt: null,
        depth: 3,
        text: "Task2",
      },
      {
        checked: false,
        checkedAt: null,
        depth: 3,
        text: "Task3",
      },
    ]);
  });
});

これでE2Eテストは完成。継続的にチェックしたいのでGitHub Actionsでも実行するように設定。

.github/workflows/playwright.yml

name: Playwright Tests
on:
  push:
    branches:
      - "*"
    tags-ignore:
      - "v*"
jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 16.x
          cache: yarn
      - name: Cache node_modules
        uses: actions/cache@v3
        with:
          path: ~/.cache/yarn
          key: ${{ runner.os }}-todo-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }}
          restore-keys: ${{ runner.os }}-todo-
      - name: Install node_modules
        if: steps.cache.outputs.cache-hit != 'true'
        run: yarn install
      - name: Install Playwright Browsers
        run: yarn playwright install --with-deps
      - name: Run Playwright tests
        run: TZ=Asia/Tokyo yarn e2e:all
      - uses: actions/upload-artifact@v3
        if: always()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

手軽に使えて良いフレームワークだったので、今後も使っていくと思った。