0
0

@testing-library/reactを使ってモーダル実装コードをテストする

Posted at

概要

@testing-library/reactを使ってモーダル実装したコードのテストコードを書いてみました。

仕様

実装内容としては、1つのページにモーダルを開くリンクと、初期状態がdisabledのボタンがあり
モーダルを開くリンクを押し、モーダルを閉じる際にボタンのdisabledを解除しボタンが押せるようにするというのが
実装ないようになります。

コード

App.tsx
import React, { useState } from "react";
import { ModalItem } from "./components/ModalItem";

export const App: React.FC = () => {
  const [isOpen, setIsOpen] = useState(false);
  const [disabled, setDisabled] = useState(true);

  const handleOpenModal = () => {
    setIsOpen(!isOpen);
  };

  const handleCloseModal = () => {
    setDisabled(false);
    setIsOpen(!isOpen);
  };

  return (
    <div>
      <p>ここはテスト用に作ったページです</p>

      <span onClick={handleOpenModal}>ここを押すとモーダルが開きます</span>
      <button disabled={disabled}>ここはボタンです</button>

      <ModalItem isOpen={isOpen} handleClose={handleCloseModal} />
    </div>
  );
};

components/ModalItem.tsx
import React from "react";
import Modal from "@mui/material/Modal";
import "./index.css";
import { Box, Typography } from "@mui/material";

type Props = {
  isOpen: boolean;
  handleClose: () => void;
};

const style = {
  position: "absolute" as "absolute",
  top: "50%",
  left: "50%",
  transform: "translate(-50%, -50%)",
  width: 400,
  bgcolor: "background.paper",
  border: "2px solid #000",
  boxShadow: 24,
  p: 4,
};

export const ModalItem: React.FC<Props> = ({ isOpen, handleClose }) => {
  return (
    <div>
      <Modal open={isOpen} onClose={handleClose}>
        <Box sx={style}>
          <Typography>ここはモーダルです</Typography>
          <button onClick={handleClose}>閉じる</button>
        </Box>
      </Modal>
    </div>
  );
};

上の仕様通りに作りました。
次はテストです。

App.test.tsx
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { App } from "./App";

test("モーダルが表示されること", () => {
  render(<App />);

  // モーダルを開くリンクが存在していること
  const targetLink = screen.getByText("ここを押すとモーダルが開きます");
  expect(targetLink).toBeInTheDocument();

  // 初期状態のボタンがdisabledになっていること
  const targetButton = screen.getByText("ここはボタンです");
  expect((targetButton as HTMLButtonElement).disabled).toStrictEqual(true);

  // モーダルを開いて、モーダルが表示されていることを確認
  fireEvent.click(targetLink);
  expect(screen.getByText("ここはモーダルです")).toBeInTheDocument();

  // モーダルの閉じるボタンを押してモーダルが非表示になっていることを確認
  fireEvent.click(screen.getByText("閉じる"));
  expect(screen.queryByText("ここはモーダルです")).not.toBeInTheDocument();
  expect((targetButton as HTMLButtonElement).disabled).toStrictEqual(false);
});

テストコードの解説

難しい部分はほとんどないのですが、
getByTextでアクションに必要な要素を取得しています。
queryByTextを使っている部分は、非表示の要素がないことを確認したい際に使用します。getByText.not.toBeInTheDocument()だと要素の取得ができないためテスト失敗します。

アクションしたい要素を取得したらfireEvent.click()でその要素をクリックすることができるので
そちらを使って簡単にテストができました。

0
0
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
0
0