Jon Harding
Jon Harding

Reputation: 4946

React Testing Library / React Router

I'm trying to test my signin page to verify after a 200 call to the API that it will redirect to our dashboard.

import { render as testRender } from '@testing-library/react';
import { ThemeProvider, Global } from '@emotion/react';
import { MemoryRouter } from 'react-router-dom';
import UserContext from '../user.context';
import { theme } from '../theme/theme';
import { globalStyles } from '../theme/globalstyles';

export const render = (component) => {
    return testRender(
        <UserContext.Provider value={{firstName: 'John', lastName: 'Doe'}}>
            <ThemeProvider theme={theme}>
                <Global styles={globalStyles} />
                <MemoryRouter>{component}</MemoryRouter>
            </ThemeProvider>
        </UserContext.Provider>
    )
}

My test is inserting an email / password and clicking the sign in button

test('Mock signin call and verify you get taken to overview page', async () => {        
    render(<SignIn />);

    userEvent.type(screen.getByTestId('input-email'), '[email protected]');
    userEvent.type(screen.getByTestId('input-password'), 'HowdyP1lgrum!');
    fireEvent.click(screen.getByTestId('button-signin'));

    await screen.findByText('user-name');
    expect(screen.getByText(/John Wayne/i)).toBeInTheDocument();
});

I have code in my Signin.jsx that looks for the status of the completed form and uses a <Redirect/> from React Router Dom to transition pages.

if (status.state === FORMSTATUS.COMPLETED) {
    if (status.resetPassword) {
        return <Redirect to={{ pathname: ROUTES.UPDATEPASSWORD, state: { email: credentials.email } }} />
    } else {
        console.log('************** Got Here ****************');
        return <Redirect to={ROUTES.OVERVIEW} />
    }
}

I can see the logged statement ****Got Here*** However it never finds the DOM in the header with the logged in user. The Redirect never seems to fire and I'm stuck with <body><div /></body>.

Am I missing something in my setup to properly test route transitions?

Upvotes: 0

Views: 2130

Answers (1)

Taghi Khavari
Taghi Khavari

Reputation: 6582

you can change your custom render to this:

//other imports
import { Router } from "react-router-dom";
import { createMemoryHistory } from "history";

export function render(
  component,
  {
    route = "/",
    history = createMemoryHistory({
      initialEntries: [route]
    }),
    ...options
  } = {}
) {
  const messages = resourceConvertor(resource);
  const userContext = createUserContext({});

  function wrapper({ children }) {
    return (
      <UserContext.Provider value={{ firstName: "John", lastName: "Doe" }}>
        <ThemeProvider theme={theme}>
          <Global styles={globalStyles} />
          <Router history={history}>{children}</Router>
        </ThemeProvider>
      </UserContext.Provider>
    );
  }

  return {
    ...testRender(component, { wrapper, ...options }),
    history
  };
}

now you can check the history to see if it's your desired route or not:

test("Mock signin call and verify you get taken to overview page", async () => {
  const { history } = render(<SignIn />);

  userEvent.type(screen.getByTestId("input-email"), "[email protected]");
  userEvent.type(screen.getByTestId("input-password"), "HowdyP1lgrum!");
  fireEvent.click(screen.getByTestId("button-signin"));

  // I don't know about these two line, usually you want to mock exteranl api call
  await screen.findByText("user-name");
  expect(screen.getByText(/John Wayne/i)).toBeInTheDocument();

  // now check to see if the url has bee redirected or not
  expect(history.location.pathname).toBe(ROUTES.OVERVIEW)
});

Upvotes: 3

Related Questions