かゆいところに手が届くTypescriptのPlaywright逆引きTips集

# はじめに
PlaywrightはMicrosoftが開発したE2Eテスト用のテストツールで、使い勝手が非常に良い。
ドキュメントも充実していて、かつ利用者も増えてきているので、基本的な使い方はGoogleで検索すれば色々な情報がサクッと出てくる。

https://playwright.dev/docs/intro

APIリファレンス的に「何ができるか」を紹介している情報は多いものの、用途別に逆引きできる情報が以外と少ないため、自分用のメモも兼ねてまとめておくことにする。

# テスト実行
## アサーション失敗時も止めずに最後まで走り切らせる
Playwrightのアサーションにはexpectを用いる。
デフォルトではアサーション失敗時にテストが停止してしまうが、一旦全テストを走り切らせたいときにはexpect.softを使う。

https://playwright.dev/docs/next/test-assertions#soft-assertions

## アサーションの文言を変更する
アサーションの文言を変更したい場合は以下のサンプルコードの2行目のように引数で指定する。

https://playwright.dev/docs/next/test-assertions#custom-expect-message

```typescript
    expect.soft(await page.getByRole('table').nth(0).getByRole('row').nth(1).getByRole('cell').nth(1).innerText()).toMatch(/^hogehogi$/);
    expect.soft(await page.getByRole('table').nth(0).getByRole('row').nth(1).getByRole('cell').nth(2).innerText(), 'テーブルの年齢が正しいこと').toMatch(/^24$/);
```

レポートのError時の表示が指定した内容に変更される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/87d438ee-a719-8fd3-d440-ee79747b1d8d.png)

## テーブル要素にピンポイントでアクセスする
例えば、以下のようなテーブル要素にアクセスする場合、tableのlocator以外にも、nth()を使って階層構造を辿ってセルの情報にアクセスすることが可能。ただし、動的に生成されるページのアサーションでnth()を使うと、位置がずれる可能性があるので注意が必要だ。

```html
<table>
  <thead>
    <tr>
      <th>id</th>
      <th>department</th>
      <th>age</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>00001</td>
      <td>hogehoge</td>
      <td>25</td>
    </tr>
  </tbody>
</table>
```

```typescript
    expect.soft(await page.getByRole('table').nth(0).getByRole('row').nth(1).getByRole('cell').nth(1).innerText()).toMatch(/^hogehoge$/);
    expect.soft(await page.getByRole('table').nth(0).getByRole('row').nth(1).getByRole('cell').nth(2).innerText()).toMatch(/^24$/);
```

## ファイルダウンロード
ダウンロードの確認には、downloadイベントを使う。

https://playwright.dev/docs/api/class-download

## ファイルのアップロード
アップロードには、locatorの```setInputFiles()```を使う。

https://playwright.dev/docs/next/api/class-locator#locator-set-input-files

locatorの特定には、以下のようにinputを指定するのが確実だろう。

```typescript
    await page.getByRole('table').locator("input[type='file']").setInputFiles('./sample1.png');
```

## test()中にコンフィグを参照する
test()の中でコンフィグを参照したい場合は、以下のように```test()```の引数に```testInfo```を渡す。
```testInfo.config```でコンフィグ情報を参照可能だ。

```diff_typescript
test.describe('サンプル', () => {
- test('サンプルテスト', async ({ page }) => {
+ test('サンプルテスト', async ({ page }, testInfo) => {
    // (中略)
  });
});
```

# コンフィグ
##  スクリーンショットで日本語を扱う
Windows上でNode.jsをインストールして動かしている場合は問題ないが、WSL2やUbuntuではデフォルトで日本語パッケージがインストールされていないため、スクリーンショットが文字化けする。日本語を使いたい場合は、以下のように日本語パッケージをインストールする。

```shell-session
$ sudo apt install language-pack-ja fontconfig fonts-ipafont
```

また、コマンド起動時にLANGを設定してあげよう

```diff_json:package.json
{
  (中略)
  "scripts": {
    (中略)
-   "playwright": "npx playwright test src/__playwright__/example.spec.ts",
+   "playwright": "LANG=ja_JP.UTF-8 npx playwright test src/__playwright__/example.spec.ts",
    (中略)
  },
  (中略)
}
```

## レポーターの設定
### レポートのディレクトリを変更する
レポートのディレクトリは、```defineConfig()```のreporter属性を以下のようにして指定が可能だ。(指定しない場合は./playwright-reportに出力する)

```diff_typescript:playwright.config.ts
export default defineConfig({
  // (中略)
  reporter: [[
    'html',
+   {
+     outputFolder: './playwright-report/html',
+   },
  ]],
  // (中略)
});
```

なお、スクリーンショットをレポートのディレクトリと同じパスに置こうとしたら、最後のレポート作成時に一度ディレクトリを削除するようで、消えてしまう。
上記のconfig設定に加え、スクリーンショット出力時に、以下のようにすることで、レポートとスクリーンショットをひとまとめにディレクトリに入れることができる(.gitignoreので指定もしやすくなる)。

```typescript
    await page.screenshot({ path: `${testInfo.config.reporter[0][1].outputFolder}/../screenshot/sample.png` });
```

### テスト成功時もレポートのWeb画面を起動する
テスト成功時もGUIで確認したい場合は以下のようにPlaywrightのコンフィグを変更する。
↑で紹介した```outputFolder```との併用も可能だ。今回は併用するケースを紹介する

```diff_typescript:playwright.config.ts
export default defineConfig({
  // (中略)
  reporter: [[
    'html',
    {
      outputFolder: './playwright-report/html',
+     open: 'always',
    },
  ]],
  // (中略)
});
```

### その他のレポーターの設定
レポーターの設定は多岐に渡るが、HTMLレポーターについては以下を参照すると他に設定可能な情報が載っている。

https://playwright.dev/docs/next/test-reporters#html-reporter

## テスト実行時にwebpackのdevServerを起動する
Reactで画面を作っている場合はローカルテスト時にwebpackでローカルサーバを立てているケースが多いと思うので、Playwrightのコンフィグでテスト実行時に勝手にサーバを起動するようにしておくと楽になる。

```diff_json:package.json
{
  (中略)
  "scripts": {
    (中略)
+   "webpackDev": "webpack-dev-server --config ./.webpackrc.dev.js",
    (中略)
  },
  (中略)
}
```

```diff_typescript:playwright.config.ts
export default defineConfig({
  // (中略)
+ webServer: {
+   command: 'npm run webpackDev',
+   url: 'http://127.0.0.1:8080/',
+   reuseExistingServer: !process.env.CI,
+ },
  // (中略)
});
```