1

I'm trying to test the redirection page when the user clicks on the button (I don't want to user jest.mock()). I created the wrapper according to test-react-library documentation:

import { FC, ReactElement, ReactNode } from "react";
import { render, RenderOptions } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom";
import userEvent from "@testing-library/user-event";

const WrapperProviders: FC<{ children: ReactNode }> = ({ children }) => {
  return <BrowserRouter>{children}</BrowserRouter>;
};

const customRender = (
  ui: ReactElement,
  { route = "/" } = {},
  options?: Omit<RenderOptions, "wrapper">
) => {
  window.history.pushState({}, "Home Page", route);
  return {
    user: userEvent.setup(),
    ...render(ui, { wrapper: WrapperProviders, ...options })
  };
};

export * from "@testing-library/react";
export { customRender as render };
export type RenderType = ReturnType<typeof customRender>;

HomePage.tsx:

import { useNavigate } from "react-router-dom";

export default function HomePage() {
  const navigate = useNavigate();

  const handleClick = () => navigate("/other");
  return (
    <>
      <h3>HomePage</h3>
      <button onClick={handleClick}>Redirect</button>
    </>
  );
}

Other.tsx:

export default function Other() {
  return <h3>Other</h3>;
}

HomePage.test.tsx:

import { render, RenderType } from "./customRender";
import HomePage from "./HomePage";
import "@testing-library/jest-dom/extend-expect";

describe("HomePage", () => {
  let wrapper: RenderType;
  beforeEach(() => {
    wrapper = render(<HomePage />, { route: "/" });
  });

  test.only("Should redirects to other page", async () => {
    const { getByText, user } = wrapper;

    expect(getByText(/homepage/i)).toBeInTheDocument();

    const button = getByText(/redirect/i);
    expect(button).toBeInTheDocument();
    user.click(button);
    expect(getByText(/other/i)).toBeInTheDocument();
  });
});

When I run the test, it fails and the page is not updated in the dom. Does jest-dom does not support the re-render of the page and update the DOM? Or this test out of scope of the testing-library ?

Slim
  • 5,527
  • 13
  • 45
  • 81

2 Answers2

1

From the code I can see that you are just rendering the HomePage component and inside of that component you don't have any logic that renders a new component based on the route changes (I suppose that you have that logic on another component). That's why when you click on the button you are not seeing the Other component rendered.

In this case I would suggest you to only make the assertions you need on the window.location object. So after you simulate the click on the button you can do:

expect(window.location.pathname).toBe("/other");
Hakim Abdelcadir
  • 1,231
  • 4
  • 15
1

I updated the custom render and add a history for it:

const WrapperProviders: FC<{ children: ReactNode }> = ({ children }) => {
  return <BrowserRouter>{children}</BrowserRouter>;
};

const customRender = (
  ui: ReactElement,
  { route = "/",
    history = createMemoryHistory({initialEntries: [route]}),
   } = {},
  options?: Omit<RenderOptions, "wrapper">
) => {
  return {
    user: userEvent.setup(),
    ...render( <Router location={history.location} navigator={history}>
         ui
        </Router>
     , { wrapper: WrapperProviders, ...options })

  };
};

and the test now passes:

describe("HomePage", () => {
  let wrapper: RenderType;
  beforeEach(() => {
    wrapper = render(<HomePage />, { route: "/" });
  });

  test.only("Should redirects to other page", async () => {
    const { getByText, user, history } = wrapper;

    expect(getByText(/homepage/i)).toBeInTheDocument();

    const button = getByText(/redirect/i);
    expect(button).toBeInTheDocument();
    await user.click(button);
    expect(history.location.pathname).toBe('/other');
});
Slim
  • 5,527
  • 13
  • 45
  • 81