2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vitestで window.open をモックしてリンクボタンの挙動をテストする

2
Posted at

はじめに

「新しいタブでURLを開く」ボタンをテストしようとしたら、window.open が jsdom では動かなくて詰まりました。

jsdom(Vitestのデフォルト環境)はブラウザAPIを完全に実装しているわけではないので、window.open をそのまま呼ぼうとすると not implemented エラーになることがあります。

そこで vi.spyOn を使ってモックする方法を整理しました。

完成コード

import { describe, it, expect, beforeEach, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom/vitest";
import { ChakraProvider } from "@chakra-ui/react";
import { UserCard } from "./UserCard";
import type { User } from "../../../shared/types/user";

describe("UserCard", () => {
  const user: User = {
    id: "testUser1",
    name: "テストユーザー1",
    description: "テストユーザーの自己紹介",
    skills: [
      { id: 1, name: "React" },
      { id: 2, name: "TypeScript" },
    ],
    githubId: "testUser1",
    qiitaId: "testUser1",
    xId: "testUser1",
    createdAt: new Date().toISOString(),
  };

  beforeEach(() => {
    render(
      <ChakraProvider>
        <UserCard user={user} />
      </ChakraProvider>
    );
  });

  it("GitHubアイコンをクリックすると正しいURLが新しいタブで開かれる", async () => {
    const openSpy = vi.spyOn(window, "open").mockImplementation(() => null);

    const button = screen.getByRole("button", { name: "GitHub Url" });
    await userEvent.click(button);

    expect(openSpy).toHaveBeenCalledWith(
      "https://github.com/testUser1",
      "_blank"
    );

    openSpy.mockRestore();
  });
});

ポイント解説

vi.spyOn(window, "open").mockImplementation(() => null)

vi.spyOnwindow.open をスパイに差し替えます。.mockImplementation(() => null) を追加することで、実際の処理(新しいタブを開く)を無効化しつつ、「どんな引数で呼ばれたか」だけを記録できます。

null を返しているのは、window.open の戻り値の型が WindowProxy | null だからです。型を合わせておくとTypeScriptに怒られません。

screen.getByRole("button", { name: "GitHub Url" })

aria-label 属性の値がボタンのアクセシブル名になります。name オプションにはコンポーネントの aria-label完全に一致する文字列を指定する必要があります。

"GitHub Url""GitHub URL" は別物として扱われます。テストが TestingLibraryElementError: Unable to find an accessible element で落ちたら、まずコンポーネントの aria-label の文字列を確認してみてください。

openSpy.mockRestore() でモックを元に戻す

テスト終了後にモックを元に戻しておかないと、後続のテストに影響が出ます。テストの最後に呼ぶか、afterEach にまとめておくと安全です。

afterEach(() => {
  openSpy.mockRestore();
});

まとめ

  • jsdomでは window.open が動かないので vi.spyOn でモックする
  • .mockImplementation(() => null) で実処理を無効化しつつ呼び出しを記録できる
  • getByRolename オプションは aria-label と完全一致が必要
  • テスト後は mockRestore() でモックを解除する
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?