Testing react-toastify with Jest & React Testing Library

144 views Asked by At

So I have a simple component with a button that opens a modal which is a react-toast. The modal get closed when a user clicks on the Close button(X) which is inbuilt in react-toastify.

Now I want to write tests for this component. The issue is that I am not able to test if the modal gets closed when the user clicks on the close button.

This is my code.

MyComponent.js

import React, { useState } from "react";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

const MyComponent = () => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const handleOpenModal = () => {
    if (!isModalOpen) {
      toast.success("This is modal content.", {
        autoClose: false,
        closeOnClick: false,
        onClose: () => setIsModalOpen(false), // Update state on close
      });
      setIsModalOpen(true);
    }
  };

  return (
    <div>
      <button onClick={handleOpenModal}>Open Modal</button>
    </div>
  );
};

export default MyComponent;

MyComponent.test.js

import React from "react";
import { render, fireEvent, waitFor, act } from "@testing-library/react";
import MyComponent from "./MyComponent";
import { ToastContainer } from "react-toastify";

// Test: Clicking close button closes modal
test("clicking close button closes modal", async () => {
  const { queryByText, getByRole } = render(
    <>
      <MyComponent />
      <ToastContainer />
    </>
  );

  const button = getByRole("button", { name: "Open Modal" });
  act(() => {
    fireEvent.click(button);
  });
  await waitFor(() => queryByText("This is modal content."));
  const closeButton = getByRole("button", { name: "close" });
  expect(closeButton).toBeInTheDocument();

  act(() => {
    fireEvent.click(closeButton);
  });

  expect(queryByText("This is modal content.")).toBeNull();
});

This is what I am getting on runnung test.

So how can I make the test run?

1

There are 1 answers

4
CodeCreater On

What you've done so far is good. You can use setTimeout to call expect after the modal is closed.

describe('MyComponent', () => {
    it('Should close modal on clicking close', async () => {
        const {getByRole, queryByText} = render(
            <>
            <MyComponent />
            <ToastContainer />
            </>
        )
        const button = getByRole('button')
        fireEvent.click(button)
        await waitFor(() => queryByText("This is modal content."))
        const closeButton = getByRole("button", { name: "close" })
        fireEvent.click(closeButton)
        setTimeout(() => {
            expect(queryByText("This is modal content.")).toBeNull();
        }, 1)
    })
})

Hope it will help.