Closed21

E2Eテストを考える

てずかてずか

現状整理

現在作っているアプリケーションのE2Eテストについて考えてみる

現在導入しているテスト

https://zenn.dev/yumemi_inc/articles/run-all-stories-as-test-with-vitest-jsdom

この記事を参考に、Storybookのplay関数をvitestで実行することでテストをしている。

現在導入しているテストの問題点

1コンポーネントのテストくらいなら問題なく通るが、幾つものコンポーネントでできた巨大なコンポーネントのテストを実行すると、挙動が不安定になる。(フォーム要素を取得できない etc...)

てずかてずか

今回実装したいテスト

フォームに正常な値(バリデーションを通る値)を入れて、正常に送信できるかどうか。

バリデーションエラー系は個別のコンポーネントや関数でテストを書いているので、今回はいわゆる正常系のテストを実装したい。Storybookのplay関数をvitestで実行するのが不安定だったので、少し実行に時間がかかったとしてもnode環境ではなく、playwrightなどを使ってブラウザ環境で実行した方がいいのでは?という気がしている。

てずかてずか

ドキュメントを読んで手を動かしてみようのコーナー

https://playwright.dev/docs/intro

自動生成されたサンプルテストを動かしてみる

いいね

てずかてずか
test("has title", async ({ page }) => {
  await page.goto("https://playwright.dev/");

  // Expect a title "to contain" a substring.
  await expect(page).toHaveTitle(/Playwright/);
});

現状のサンプルテストこんな感じだけど、ローカルで立ち上げたアプリでテストしたいな

てずかてずか
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はスター数とか微妙なので公式の方法でモックすることにした。

てずかてずか

モックできた

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 });
    }
  });
};
このスクラップは3ヶ月前にクローズされました