How can I test if a prop is passed to child?
Asked Answered
S

2

9

My component looks something like this: (It has more functionality as well as columns, but I have not included that to make the example simpler)

const WeatherReport: FunctionComponent<Props> = ({ cityWeatherCollection, loading, rerender }) => {
  /* some use effects skipped */
  /* some event handlers skipped */

  const columns = React.useMemo(() => [
    {
      header: 'City',
      cell: ({ name, title }: EnhancedCityWeather) => <Link to={`/${name}`} className="city">{title}</Link>
    },
    {
      header: 'Temp',
      cell: ({ temperature }: EnhancedCityWeather) => (
        <div className="temperature">
          <span className="celcius">{`${temperature}°C`}</span>
          <span className="fahrenheit">{` (~${Math.round(temperature * (9 / 5)) + 32}°F)`}</span>
        </div>
      )
    },
    {
      header: '',
      cell: ({ isFavorite } : EnhancedCityWeather) => isFavorite && (
        <HeartIcon
          fill="#6d3fdf"
          height={20}
          width={20}
        />
      ),
    },
  ], []);

  return (
    <Table columns={columns} items={sortedItems} loading={loading} />
  );
};

Now, I wrote some tests like this:

jest.mock('../../../components/Table', () => ({
  __esModule: true,
  default: jest.fn(() => <div data-testid="Table" />),
}));

let cityWeatherCollection: EnhancedCityWeather[];
let loading: boolean;
let rerender: () => {};

beforeEach(() => {
  cityWeatherCollection = [/*...some objects...*/];

  loading = true;
  rerender = jest.fn();

  render(
    <BrowserRouter>
      <WeatherReport
        cityWeatherCollection={cityWeatherCollection}
        loading={loading}
        rerender={rerender}
      />
    </BrowserRouter>
  );
});

it('renders a Table', () => {
  expect(screen.queryByTestId('Table')).toBeInTheDocument();
});

it('passes loading prop to Table', () => {
  expect(Table).toHaveBeenCalledWith(
    expect.objectContaining({ loading }),
    expect.anything(),
  );
});

it('passes items prop to Table after sorting by isFavorite and then alphabetically', () => {
  expect(Table).toHaveBeenCalledWith(
    expect.objectContaining({
      items: cityWeatherCollection.sort((item1, item2) => (
        +item2.isFavorite - +item1.isFavorite
        || item1.name.localeCompare(item2.name)
      )),
    }),
    expect.anything(),
  );
});

If you check my component, it has a variable called columns. I am assigning that variable to Table component.

I think, I should test that columns are being passed as props to the Table component. Am I thinking right? If so, can you please tell me how can I write a test case for that?

Also, it will be helpful if you can suggest me how can i test each cell declared inside columns property.

Sailer answered 21/11, 2020 at 2:16 Comment(3)
Are you familiar with this already? reactjs.org/docs/typechecking-with-proptypes.htmlFloatfeed
@TonyDrummond I am new to writing test cases. But I have been using PropTypes from much more time.Sailer
Does this answer your question? Test if a component is rendered with the right props with react-testing-libraryPatinated
T
14

It is not recommended to test implementation details, such as component props, with React Testing Library. Instead you should be asserting on the screen content.


Recommended

expect(await screen.findByText('some city')).toBeInTheDocument();
expect(screen.queryByText('filtered out city')).not.toBeInTheDocument();

Not Recommended

If you want to test props anyways, you can try the sample code below. Source

import Table from './Table'
jest.mock('./Table', () => jest.fn(() => null))

// ... in your test
expect(Table).toHaveBeenCalledWith(props, context)

You might consider this approach mainly on the two following scenarios.

You already tried the recommended approach but you noticed the component is:

  1. using legacy code and because of that it makes testing very hard. Refactoring the component would also take too long or be too risky.
  2. is very slow and it drastically increases the testing time. The component is also already tested somewhere else.

have a look at a very similar question here

Tyler answered 21/11, 2020 at 4:41 Comment(8)
Thank you for helping me again. I have done some research on this and I think Kent C. Dodds is giving some confusing statements. He said: "Test your components as if a real user is testing them". So, always expect some text or similar to be present on the screen. But then the code that you provided is also from him. There he is testing a component's props (which is not what a user will test). He added a statement with the code that: "My mocks are normally something like the code that is given".Sailer
Also, consider a scenario, where all the common components are well tested. Now I am writing some component that uses those common components. Is it my component's responsibility that each component used inside it should function as how it should? I believe no. Because those components are really well tested. The only thing I think, my component should be worried about is: orchestrating those different components to work together as expected. Then what should I test for? The functionality as a developer or the ui part (which has been already tested)?Sailer
It is difficult time for me take such decisions. If you can help me with those questions, then I am preety much done! Thank you.Sailer
Kent C. Dodds is giving some confusing statements you should read the whole twitter thread, he clearly says he does not recommended the given code but he provided it anyways to help out. Is it my component's responsibility that each component used inside it should function as how it should? no, but you dont need to mock them either, unless they are extremely heavy components.Tyler
The only thing my component should be worried about is: orchestrating > give that a try, add a few prop tests. You will quickly notice that your tests become a bit harder to maintain when you have to change implementation details. When you get to that point, decide what you prefer... I tested component props for 2 years before I made the switch. Then what should I test for? > Think about what your pull request is adding and how you can validate that in a test.Tyler
Got it! Now I understand how to split up my tests. I will test all the common components to check if required functionality is working fine. And then I will test all the pages. In the test of pages, I won't worry about any implementation details or functional details of any particular component. Instead I will only test: what the user will expect when he do something. Thanks for the detailed explanation.Sailer
Nice! I edited my question to hopefully make the trade offs a bit clearer.Tyler
Thank you. I have noticed the change in the answer and will remember that.Sailer
B
2

You can use the props() method, doing something like this:

 expect(Table.props().propYouWantToCheck).toBeFalsy();

Just doing your component.props() then the prop you want, you can make any assert with it.

Buerger answered 21/11, 2020 at 2:45 Comment(4)
Thanks for trying to answer my question. But if you check the test file very first line, you can see that Table actually does not render. It is mocked. In this case also, will I receive the props?Sailer
I'm not one hundred percent sure, but I think that you can change this line to: default: jest.fn((props) => <div ...props data-testid="Table" />), and still be able to verify it. But since you are trying to verify the table rendering itself, you could instead of mocking the table, mock the data or the fetch request that is passed to the table.Rothman
The structure of my tests won't need me to render the table. Table component is already well tested and working fine. That's why I am mocking the Table. I will try to add props to the mocked version and will check if it has 4 columns, since my actual component is passing 4 columns. Can you please let me know, what else shall I test? Basically, I am learning how to test components, so I am asking some silly questions. It will also be helpful, if you can let me know: How can I test cell property of columns?Sailer
@OtacílioMaia you might be referring to a different testing frameworkTyler

© 2022 - 2024 — McMap. All rights reserved.