React + Jestでコンポーネントの分岐出力をテストする

条件分岐でコンポーネントの出し分けをしている時に正しくコンポーネントが出ているかどうかに使えるやつ
UI ロジックのリグレッションテストで使える
分岐結果の出力を見てるだけなのでテストとして壊れづらく、運用しやすいと考えている

確認環境

Next.js で確認してるけど素の React でも同じだと思う

Env Ver
@swc/core 1.2.133
@swc/jest 0.2.17
jest 27.4.7
next 12.0.8
react 17.0.2
react-dom 17.0.2
react-test-renderer 17.0.2
typescript 4.5.4

テスト対象

テストのためにコンポーネントを細かく export すると名前空間が汚染されるのが悩み…

type BaseProps = {
  id: string;
};

type SwitchExampleProps = BaseProps & {
  display: 'Foo' | 'Bar';
};

export const Foo = (props: BaseProps) => {
  return (
    <div id={props.id}>
      <p>Foo</p>
    </div>
  );
};

export const Bar = (props: BaseProps) => {
  return (
    <div id={props.id}>
      <p>Bar</p>
    </div>
  );
};

export const SwitchExample = (props: SwitchExampleProps) => {
  if (props.display === 'Foo') {
    return <Foo id={props.id} />;
  } else {
    return <Bar id={props.id} />;
  }
};

テストコード

react-testing-library の .toHaveAttribute().toHaveDisplayValue() を書き連ねるより圧倒的に楽で保守性も良いと思う

import TestRenderer from 'react-test-renderer';
import { Bar, Foo, SwitchExample } from './SwitchExample';

type TestCase = {
  name: string;
  param: Parameters<typeof SwitchExample>[0];
  actual: JSX.Element;
};

describe('SwitchExample', () => {
  const testCaseItems: TestCase[] = [
    {
      name: 'Foo',
      param: {
        id: 'hoge',
        display: 'Foo',
      },
      actual: <Foo id={'hoge'} />,
    },
    {
      name: 'Bar',
      param: {
        id: 'piyo',
        display: 'Bar',
      },
      actual: <Bar id={'piyo'} />,
    },
  ];

  testCaseItems.forEach((item) => {
    // eslint-disable-next-line jest/valid-title
    it(`switched condition ${item.name}`, () => {
      const result = TestRenderer.create(
        <SwitchExample id={item.param.id} display={item.param.display} />
      );
      const actual = TestRenderer.create(<>{item.actual}</>);

      expect(result.toJSON()).toStrictEqual(actual.toJSON());
    });
  });
});

参考記事