🔰

【Next.js, Vitest】テストコード書きたくなったのでVitestに入門する

に公開

実装進めてたらついにテストコードがないと不安になったのでVitestで書きます。

テストコードが必要だと思った理由

microCMSの投稿画面にオリジナルボタンを設置したい。

iframe連携をする必要がある

Next.jsでページを作ってiframeで読み込ませる(microCMSの拡張フィールドを使う)

middleware.tsでアクセスを制御
ローカル環境(localhost)とmicrCMSの投稿画面だけアクセスさせたい

これで網羅できとるんか(不安...)

そうだ、テスト、書こう

Vitestとは? Jestデビューするつもりでした

chatGPTにVitestのが良い。と言われたので軽く調べる。

・Jest互換性がある
・jsx、Typescriptに対応
・高速
・Viteなくても使える

とりあえず使ってみる。

https://vitest.dev/

セッティング

インストール

npm install -D vitest

scriptsにtestを追加

{
  "scripts": {
    "test": "vitest"
  }
}

※ JSX、import alias(@/)などをテストする場合はvite.config.tsを追加する必要があるっぽい。今回テストするのはmiddleware.tsだけで、サーバーサイドで処理されるので必要なさそう。

試してみる

ファイルの置き場所の指定はないらしいので、
今回はmiddleware.test.tsをmiddleware.tsと同階層に設置。

公式のサンプルコードをコピペ。

middleware.ts

export function sum(a: number, b: number) {
  return a + b;
}

middleware.test.ts

import { expect, test } from "vitest";
import { sum } from "./middleware"; // 足し算関数を一次的に書いてます。

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(3);
});

で、npm run test...

とりあえず動いたぞ。おもろい。

middleware.ts、どこをテストしたら良い?

テストしたいコードがこちら。

middlreware.tsでアクセス制御。

通常のアクセスは403(閲覧禁止)。
ローカル環境(localhost)とmicrCMSの投稿画面だけ許可。

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function isAllowed(request: NextRequest) {
  // ローカルからのアクセスを許可
  const { hostname } = request.nextUrl;
  const isLocal = hostname.includes("localhost");

  // microCMSからのアクセスを許可
  const referer = request.headers.get("referer") || "";
  const isMicroCMS =
    referer.includes("microcms.io") || referer.includes("microcms.app");

  return isLocal || isMicroCMS;
}

export function middleware(request: NextRequest) {
  if (!isAllowed(request)) {
    return new NextResponse("Forbidden", { status: 403 });
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/custom-field/:path*"],
};

テスト項目

chatGPTにも聞いたので大丈夫だろう。肝心のテストコードは間違ってたけど。
要するにisAllowed()をテストしたい。

  1. ローカル開発環境(ホストがlocalhost)からのアクセス
    → 通す⭕️

  2. microCMS画面からのアクセス(リファラにmicrocms.ioが含まれている)
    → 通す⭕️

  3. この2つ以外
    → 通さない❌

この結果になればおkってことね。

テスト実装

やります。

...。

middleware.tsってどうやってテストするんだ?

神。
https://zenn.dev/moozaru/articles/2631c18c970906

書いた。

import { describe, expect, it } from "vitest";
import { isAllowed } from "./middleware";
import { NextRequest } from "next/server";

describe("middlewareのアクセス制御", () => {
  it("ローカル環境(localhost)を許可", () => {
    const request = new NextRequest(
      "http://localhost:3000/custom-field/button"
    );
    expect(isAllowed(request)).toBe(true);
  });

  it("refererにmicroCMSが含まれていたら許可", () => {
    const request = new NextRequest(
      "https://hoge-fuga.microcms.io/apis/testurl/create",
      {
        headers: {
          referer: "microcms.io",
        },
      }
    );
    expect(isAllowed(request)).toBe(true);
  });

  it("それ以外はNG", () => {
    const request = new NextRequest("http://hogefugapiyo.com");
    expect(isAllowed(request)).toBe(false);
  });
});

「動いた!!!!」

無駄なコミットが減りそうなので積極的に書く。
引き続き勉強します。

Discussion