E2Eテストを考える
現状整理
現在作っているアプリケーションのE2Eテストについて考えてみる
現在導入しているテスト
この記事を参考に、Storybookのplay関数をvitestで実行することでテストをしている。
現在導入しているテストの問題点
1コンポーネントのテストくらいなら問題なく通るが、幾つものコンポーネントでできた巨大なコンポーネントのテストを実行すると、挙動が不安定になる。(フォーム要素を取得できない etc...)
今回実装したいテスト
フォームに正常な値(バリデーションを通る値)を入れて、正常に送信できるかどうか。
バリデーションエラー系は個別のコンポーネントや関数でテストを書いているので、今回はいわゆる正常系のテストを実装したい。Storybookのplay関数をvitestで実行するのが不安定だったので、少し実行に時間がかかったとしてもnode環境ではなく、playwrightなどを使ってブラウザ環境で実行した方がいいのでは?という気がしている。
ツールの選定
Playwrightでいいかな?
ドキュメントを読んで手を動かしてみようのコーナー
自動生成されたサンプルテストを動かしてみる
いいね
test("has title", async ({ page }) => {
await page.goto("https://playwright.dev/");
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});
現状のサンプルテストこんな感じだけど、ローカルで立ち上げたアプリでテストしたいな
import { defineConfig } from '@playwright/test';
export default defineConfig({
// 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,
stdout: 'ignore',
stderr: 'pipe',
},
});
こんな感じでできそう
import { expect, test } from "@playwright/test";
const url = "http://127.0.0.1:3000";
test("has title", async ({ page }) => {
await page.goto(url);
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Create Next App/);
});
テスト通った
コンポーネントの近くにテストを置きたいから、.spec.ts
がplaywrightで実行するファイルで、.test.ts
がvitestで実行するファイルとか区別できないかな?
export default defineConfig({
/* .spec.tsの拡張子を持つファイルのみをplaywrightで実行 */
testMatch: "/src/**/*.spec.ts",
configファイルにこれ追加したらいけた
ページロード直後のtext-inputの入力操作が不安定。入力してもFocusが外れた瞬間入力した文字が消えたりする
正しい方法かはわからんが、ページを開いた後に1秒待ってからフォームへの入力操作を開始することで安定するようになった
await page.goto(`/`);
// 少し待たないと、値が正常に入力されないことがある
await page.waitForTimeout(1000);
テスト書いていく
PlaywrightでAPIをモックしたい
playwright-mswなるものがあるらしい
msw使わなくても良さそうか?
playwright-mswはスター数とか微妙なので公式の方法でモックすることにした。
GraphQLのモック方法を調査
モックできた
const mockApi = async (page: Page) => {
await page.route(url, async (route) => {
const req = route.request().postDataJSON();
if (req.operationName === "hogehoge") {
const json = {
data: {
__typename: "Query",
queryWithAuth: {
__typename: "QueryWithAuth",
data: ...,
},
},
};
await route.fulfill({ json });
}
});
};
CIでも実行できた。
これにて一件落着