小道具が子供に渡されるかどうかをテストするにはどうすればよいですか?

Nov 20 2020

私のコンポーネントは次のようになります:(列だけでなくより多くの機能がありますが、例を簡単にするためにそれを含めていません)

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} />
  );
};

今、私はこのようないくつかのテストを書きました:

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(),
  );
});

コンポーネントを確認すると、columnsという変数があります。その変数をテーブルコンポーネントに割り当てています。

列が小道具としてTableコンポーネントに渡されていることをテストする必要があると思います。私は正しいと思いますか?もしそうなら、そのためのテストケースをどのように書くことができるか教えていただけますか?

また、columnsプロパティ内で宣言された各セルをテストする方法を教えていただければ助かります。

回答

1 Doug Nov 21 2020 at 04:41

React Testing Libraryを使用して、コンポーネントの小道具などの実装の詳細をテストすることはお勧めしません。代わりに、画面のコンテンツを主張する必要があります。


推奨

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

推奨されません

とにかく小道具をテストしたい場合は、以下のサンプルコードを試すことができます。ソース

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

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

このアプローチは、主に次の2つのシナリオで検討できます。

推奨されるアプローチをすでに試しましたが、コンポーネントが次のとおりであることに気付きました。

  1. レガシーコードを使用しているため、テストが非常に困難になります。コンポーネントのリファクタリングも時間がかかりすぎるか、リスクが高すぎます。
  2. は非常に遅く、テスト時間が大幅に増加します。コンポーネントはすでにどこかでテストされています。

ここで非常によく似た質問を見てください

2 OtacílioMaia Nov 21 2020 at 02:45

このprops()メソッドを使用して、次のようにすることができます。

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

component.props()を実行してから、必要な小道具を実行するだけで、任意のアサートを行うことができます。