Playwright試してみる

## 概要
これまでE2Eテストをやったことがなかったが、`Playwright`が話題に上がったため簡単に試して使い勝手を見たいと思う。

https://zenn.dev/mikana0918/articles/b6eb66377fb25a

少し古いもののわかりやすい記事なので参考に上げておく。

## 開始方法

### 1. 必要なものをインストールする
```bash
npm i -D playwright @playwright/test

# Chromium、Firefox、WebKit などをインストールします
npx playwright install
```

### 2. 基本的な設定を行う
設定ファイルを準備する。
下記リンクからとってきました。

https://playwright.dev/docs/test-configuration

```ts:playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // Look for test files in the "tests" directory, relative to this configuration file.
  testDir: 'tests',

  // Run all tests in parallel.
  fullyParallel: true,

  // Fail the build on CI if you accidentally left test.only in the source code.
  forbidOnly: !!process.env.CI,

  // Retry on CI only.
  retries: process.env.CI ? 2 : 0,

  // Opt out of parallel tests on CI.
  workers: process.env.CI ? 1 : undefined,

  // Reporter to use
  reporter: 'html',

  use: {
    // Base URL to use in actions like `await page.goto('/')`.
    baseURL: 'http://127.0.0.1:3000',

    // Collect trace when retrying the failed test.
    trace: 'on-first-retry',
  },
  // Configure projects for major browsers.
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
  // Run your local dev server before starting the tests.
  webServer: {
    command: 'npm run start',
    url: 'http://127.0.0.1:3000',
    reuseExistingServer: !process.env.CI,
  },
});
```

私の場合は、3000番に別のアプリが常駐しているため、3001番にポートを変更しました。

### 3. package.jsonにコマンドを追記する
npmにコマンドを追加する。

```diff_json
  "scripts": {
    "dev": "next dev --turbopack",
    "build": "next build",
    "start": "next start -p 3001",
    "lint": "next lint",
+    "test": "npx playwright test"
  }
```

### 4. 適当にテストを作成する。
今回は、スクリーンショットを保存するように作っています。

testsディレクトリは、srcと同じ位置に作っていますが設定から変更可能なはずです。

```ts:tests/redirect.spec.ts
import { test, expect } from '@playwright/test';

// 各テスト終了後にスクリーンショットを撮るグローバルフック
test.afterEach(async ({ page }, testInfo) => {
  // テストの状態に応じてプレフィックスを設定（成功: pass-, 失敗: fail-）
  const prefix = testInfo.status === 'passed' ? 'pass-' : 'fail-';
  // タイトルからファイル名として不適切な文字を除去（任意の処理）
  const sanitizedTitle = testInfo.title.replace(/[^a-zA-Z0-9]/g, '_');
  // スクリーンショットの保存先とファイル名
  await page.screenshot({
    path: `screenshots/${prefix}${sanitizedTitle}.png`,
    fullPage: true,
  });
});

test('root ("/") にアクセスしたら /form にリダイレクトされる', async ({
  page,
}) => {
  await page.goto('/');
  await expect(page).toHaveURL(/\/form$/);
});

test('"/form" ページは存在する', async ({ page }) => {
  await page.goto('/form');
  await expect(page.locator('h1')).toBeVisible();
});

test('存在しないパスにアクセスした場合、Next.js の404ページが表示される', async ({
  page,
}) => {
  await page.goto('/non-existent', { waitUntil: 'load' });
  await expect(page.locator('text=404')).toBeVisible();
});
```

### 5. 開発サーバを起動する
```bash
npm run dev
```
起動していない場合に実行すると、存在しないエラーが出続けます

### 6. テストを実行する
```bash
npm run test

> guest-log@0.1.0 test
> npx playwright test


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

To open last HTML report run:

  npx playwright show-report
```

うまくいくとこのように表示され、表示されたコマンドを実行することで適宜レポートを確認できる。
また、プロジェクトルートにスクリーンショットが作成されたことも確認できる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3125890/fce77da9-7a60-4c73-967a-6fb3146e3413.png)

## まとめ
自動でスクリーンショット取ってくれることや、自分でChromium、Firefox、WebKit等を引っ張ってきてインストールしなくてよいのはめちゃくちゃ楽だと感じた。