元営業WEBエンジニアのアプリ開発日記

営業出身のWEB系エンジニアが気になったものから作ってはメモを残してくブログ

React Context.Consumerをモック化

概要

jestで単体テスト書いてる時にReactのContext.Consumerをモック化という壁にぶつかったんでメモしとく

実装

テストしたいコンポーネント

こんな感じでConsumer使って変数とかメソッド渡してる奴をモック(スタブ)にしたい。

import React from "react";
import ThemeContext from "./theme-context";

const ThemeTogglerButton = () => {
  // The Theme Toggler Button receives not only the theme
  // but also a toggleTheme function from the context
  return (
    <ThemeContext.Consumer>
      {({ theme, toggleTheme }) => (
        <button
          onClick={toggleTheme}
          style={{ backgroundColor: theme.background }}>
          Toggle Theme
        </button>
      )}
    </ThemeContext.Consumer>
  );
};

export default ThemeTogglerButton;

こんな感じでReact.createContextしてる

import React from "react";
import { themes } from "./themes";

// Make sure the shape of the default value passed to
// createContext matches the shape that the consumers expect!
const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => { },
});

export default ThemeContext;

今回あんまり重要じゃないけどthemesはこんな感じ

export const themes = {
  dark: {
    background: "#222222",
    foreground: "#ffffff",
  },
  light: {
    background: "#eeeeee",
    foreground: "#000000",
  },
};

テストコード

色々試行錯誤したけど、jest.mockをimportの後に記載するといい感じでモック(スタブ)にしてくれた!

import { mount, shallow } from "enzyme";
import React from "react";
import ThemeTogglerButton from "../../../src/containers/context/theme-toggler-button";
/** ThemeContext.Consumerをモック化 */
let theme: any;
let toggleTheme: jest.Mock<{}>;
jest.mock("../../../src/containers/context/theme-context", () => {
  return {
    Consumer: (props: any) => props.children({ theme, toggleTheme }),
  };
});

describe("theme-toggler-button.tsx", () => {
  beforeEach(() => {
    jest.resetModules();
    theme = {
      background: "green",
    };
    toggleTheme = jest.fn();
  });
  it("snapshot test", () => {
    /** 準備 */
    /** 実行 */
    const wrapper = mount(<ThemeTogglerButton />);
    expect(wrapper).toMatchSnapshot();
    /** 検証 */
  });

  it("onClick test", () => {
    /** 準備 */
    /** 実行 */
    const wrapper = mount(<ThemeTogglerButton />);
    wrapper.simulate("click");
    /** 検証 */
    // ちゃんと自分で用意したメソッドが呼び出されてる!!
    expect(toggleTheme).toBeCalledTimes(1);
  });
});

まとめ

英語のサイト見て色々検証したけどうまくいかず。。。。
describe内でjest.mock記載してもうまくいかないし、、、
とりあえずこれでやりたいことはできてる&もう悩みたくないのでとりあえずこれで行くとする

ちなみに悩んだ歴史