yikegaya’s blog

yikegayaのブログ

useEffect、useStateでhttpリクエストを飛ばしてrenderする時のテスト

useEffect、useStateでhttpリクエストを飛ばしてレスポンスの内容を元にテーブルの内容を描画する画面を書いていた。

で、レスポンスを元に表示した内容をテストしたかった。よくありそうな話だしすんなりいくだろう、、と思ったら思いの他苦戦したので作業内容メモ。

使っていたテストフレームワークはjestとenzyme。

まずenzymeでuseStateやHttpリクエストのmockを使ったやり方を探すがうまくいかず。

クラスコンポーネントであればsetStateして内容作ればそれでいいような気もしたけど、関数コンポーネントで同じようなやり方を探して試してもなかなかうまくいかず。

最終的に以下のスタックオーバフローを参考に書いた。

stackoverflow.com

大体こういう内容。

本体

const Index = () => {
  const [hoges, setHoges] = useState([]);

  useEffect(() => {
    async function fetchHoge() {
      const hoges = await axios.get<Hoge[]>(
        '/api/v1/hoge',
      );
      setHoge(hoges.data);
    }
    fetchHoges();
  }, []);
  return(
    <>
      <table>
        <thead>
          <tr>
            <th>hoge1</th>
            <th>hoge2</th>
            <th>hoge3</th>
          </tr>
        </thead>
        <tbody>
          {hoges.map((hoge, i) => (
            <tr key={i}>
              <td>{hoge.hoge_str1}</td>
              <td>{hoge.hoge_str1}</td>
              <td>{hoge.hoge_str1}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

テスト

  test('render table contents', async () => {
    const fake_params = [{hoge_str1: "hoge_str1",
                         hoge_str2_: "hoge_str2_",
                         hoge_str3: "hoge_str3"}]
    const axiosGetSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: fake_params });
    let component;
    await act(async () => {
      component = renderer.create(<Index ></Index>);
    });
    expect(axiosGetSpy).toBeCalledWith('/api/v1/hoge');
    expect(component.toJSON()).toMatchSnapshot();
    axiosGetSpy.mockRestore();
  });

jestのspyonmockResolvedValueOnceを使い。axiosのget関数をモックにする。これでuseEffectから呼ばれるget関数がモックになって、componentをrenderする時にテスト用paramの内容が表示される。

toMatchSnapshotで出力されたDOMの内容を見ても想定通りだったのでうまくいっていそう。

なんかReactのテストちゃんとやろうとするとハマるな。Railsのcapybara感覚でやってもすんなりいかないこともあるのでjestの公式ドキュメントくらいは目を通した方が良さそう。。