こんにちは、なかにしです。
今回はE2Eテストを試してみようと思います!
E2Eテストとは
フロントエンドテストの中でも最終段階で行われるテストです。
ユーザーの視点に立ち、アプリケーション全体の動作を確認することで、機能の一貫性と信頼性を保証します。
ライブラリ選定
有名どころだと、以下があります。
・Selenium
・Cypress
・playwright
今回はplaywrightを使用します。
playwrightの特徴は、以下です。
・Microsoft で開発およびメンテナンスが行われている、Node.js ベースの E2E テスト自動化フレームワーク
・マルチブラウザ対応(Chrome,Edge,Firefoxなど)
・モバイル用ブラウザも対応
・導入が簡単
CypressやSeleniumは使用したことがあったので、
playwrightも使ってみたいなーと思ったのが本音です。
テストを実施する
初期設定~導入
今回はNext.jsのアプリを対象として、E2Eテストを実施していきます。
まずは、Next.jsのアプリを用意します。
npx create-next-app念のため、サーバが起動するか確認します。
npm run dev初期画面が表示されることを確認したら、playwrightを導入していきます。
npm init playwright@latest▽どのディレクトリに導入しますか?などを聞かれるので答えていきます。

▽ 終わりました。
Happy hacking!と言われたので楽しみます。

▽ testディレクトリ配下に、サンプル用のテストが書かれています。
3~8行目では、playwrightのページへ遷移し、Titleタグに「Playwright」という文字があるかを確認しているみたいですね。

テストの実行(サンプル)
それでは、先ほど作成されたサンプル用のテストを実行してみます。
以下コマンドで、testディレクトリ配下のテストをすべて実行します。
npx playwright test▽ 終わったみたいです。

結果を見るには以下コマンドを打てと言われているので、確認します。
npx playwright show-report▽ 結果が表示されました。
サンプルのコードでは、「has title」と「get started link」の2つのテストがありましたので、それが各ブラウザで実行されているようです。

今回はchromium、firefox、webkitで実行されています。
WebKitというと、Safariに使用されているHTMLレンダリングエンジンですね。
このあたりのブラウザ設定は、playwright.config.tsから変更することができます。
▽ 現在は chromium、firefox、webkitのみコメントアウトが外されています。
他のブラウザも、コメントアウトを外すことで実行できます。
// 35行目~  
/* Configure projects for major browsers */
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
    /* Test against mobile viewports. */
    // {
    //   name: 'Mobile Chrome',
    //   use: { ...devices['Pixel 5'] },
    // },
    // {
    //   name: 'Mobile Safari',
    //   use: { ...devices['iPhone 12'] },
    // },
    /* Test against branded browsers. */
    // {
    //   name: 'Microsoft Edge',
    //   use: { ...devices['Desktop Edge'], channel: 'msedge' },
    // },
    // {
    //   name: 'Google Chrome',
    //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },
    // },
  ],UIモードを使用すると、ブラウザを使用してテストの実行をしたり、ログやエラーの詳細を見ることができます。公式もオススメしている方法です。
npx playwright test --ui▽ ブラウザが立ち上がり、手動実行できる

テストの実行(オリジナル)
基本的な使い方も分かったので、オリジナルのテストを書いていこうと思います。
今回は、以下の処理をテストしてみたいと思います。
・ボタンを押したらRoute HandlersにGETリクエストを投げる
・Route HandlersからJSON Placeholderにリクエストを投げ、データを取得する
▽ まずはボタンを用意します。
"use client";
import styles from "./page.module.css";
export default function Home() {
  const requestToAPIRoute = async () => {
    const response = await fetch("/api/getJsonData");
    const data = await response.json();
    console.log(data);
  };
  return (
    <main className={styles.main}>
      <div>
        <button onClick={requestToAPIRoute}>
          API Routeにリクエストするボタン
        </button>
      </div>
    </main>
  );
}▽ Route Handlersを用意します。
import { NextResponse } from "next/server";
export async function GET() {
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  const data = await response.json();
  return NextResponse.json(data);
}テストを用意します。
今回は、2種類用意しました。
テスト① API側をモック化し、ブラウザの挙動のみにフォーカスしたテスト
テスト② API側をモック化せず、実際の動きにフォーカスしたテスト
▽ テスト①
import { expect, test } from "@playwright/test";
test("APIボタンのテスト", async ({ page }) => {
  // ページに移動
  await page.goto("http://localhost:3000/");
  // ボタンが配置されているか確認
  const button = await page.locator("button");
  await expect(button).toBeVisible();
  // ボタンのテキストが正しいか確認
  await expect(button).toHaveText("API Routeにリクエストするボタン");
  // APIリクエストのモックを設定
  await page.route("http://localhost:3000/api/getJsonData", (route) => {
    route.fulfill({
      status: 200,
      body: JSON.stringify({ message: "Success" }),
    });
  });
  // ボタンをクリック
  await button.click();
  // コンソールにAPIリクエストの結果が出力されるか確認
  page.on("console", (msg) => {
    if (msg.type() === "log") {
      expect(msg.text()).toContain("Success");
    }
  });
});▽ テスト②
import { expect, test } from "@playwright/test";
test("API Routeへリクエストが飛ぶかテスト", async ({ page }) => {
  await page.goto("http://localhost:3000/");
  // ボタンが配置されているか確認
  const button = await page.locator("button");
  await expect(button).toBeVisible();
  // ボタンのテキストが正しいか確認
  await expect(button).toHaveText("API Routeにリクエストするボタン");
  // ボタンをクリック
  await button.click();
  // コンソールにAPIリクエストの結果が出力されるか確認
  const consoleMessage = await page.waitForEvent("console");
  if (consoleMessage.type() === "log") {
    const messageText = consoleMessage.text();
    // 実際に取得されるデータの中身をチェック
    expect(messageText).toContain("est rerum tempore");
  }
});▽ どちらのテストも成功しました。

さいごに
各ブラウザで手軽にテストが実行できるのはいいですね!
導入やコマンドが簡単なのも個人的に好みです。
私はChromeをメインで使用しているので、個人アプリだとSafariやEdgeでの確認をつい怠ってしまうのですが、これだけ簡単に導入できると、ちょっと頑張って書いてみようと思えますね。
テストはアプリの品質に直結するので、ガツガツ書いて慣れていこうと思います。
今回はここまで!
Enjoy Hacking!!



