I have the following component that I'm trying to test with react-testing-library:

const PasswordIconButton = ({
  stateString
}) => {
  const { state, dispatch } = useContext(Store);
  const showPassword = getObjectValue(stateString, state);
  const toggleShowPassword = event => {
    event.preventDefault();
    dispatch(toggleBoolean(stateString, !showPassword));
  };
  return (
    <Layout
      showPassword={showPassword}
      toggleShowPassword={toggleShowPassword}
    />
  );
};
export default PasswordIconButton;

const Layout = ({
  showPassword,
  toggleShowPassword
}) => {
  return (
    <IconButton onClick={toggleShowPassword} data-testid="iconButton">
      {showPassword ? (
        <HidePasswordIcon data-testid="hidePasswordIcon" />
      ) : (
        <ShowPasswordIcon data-testid="showPasswordIcon" />
      )}
    </IconButton>
  );
};

This works exactly as intended in production. If the user clicks the button then it calls toggleShowPassword() which toggles the value of boolean const showPassword.

If showPassword is equal to false and the user clicks the button, I can see that the <ShowPasswordIcon /> is removed and <HidePasswordIcon /> appears. Both have the correct data-testid attributes set.

I'm attempting to test the component will the following test:

import React from "react";
import {
  render,
  cleanup,
  fireEvent,
  waitForElement
} from "react-testing-library";

import PasswordIconButton from "./PasswordIconButton";

afterEach(cleanup);

const mockProps = {
  stateString: "signUpForm.fields.password.showPassword"
};

describe("<PasswordIconButtonIcon />", () => {
  it("renders as snapshot", () => {
    const { asFragment } = render(<PasswordIconButton {...mockProps} />);
    expect(asFragment()).toMatchSnapshot();
  });

  //
  // ISSUE IS WITH THIS TEST:
  // ::::::::::::::::::::::::::

  it("shows 'hide password' icon on first click", async () => {
    const { container, getByTestId } = render(
      <PasswordIconButton {...mockProps} />
    );
    const icon = getByTestId("iconButton");
    fireEvent.click(icon);
    const hidePasswordIconTestId = await waitForElement(
      () => getByTestId("hidePasswordIcon"),
      { container }
    );
    expect(hidePasswordIconTestId).not.toBeNull();
  });
});

The shows 'hide password' icon on first click test always fails and I'm not sure why. The mockProps are definitely correct and work perfectly in production.

What am I missing here?

1 Answers

0
GCM On

I figured it out... The issue is that I needed to wrap the component in the context provider as const { state, dispatch } = useContext(Store); won't work properly without it.

So I changed the render to:

    const { container, getByTestId } = render(
      <StateProvider>
        <PasswordIconButton {...mockProps} />
      </StateProvider>
    );`

And now the test passes fine.