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
記載してもうまくいかないし、、、
とりあえずこれでやりたいことはできてる&もう悩みたくないのでとりあえずこれで行くとする
ちなみに悩んだ歴史
- 有力そうな3サイトを参考に実装もうまくいかず。。
- material-uiを疑う日々
export default withStyles(style)(Login);
のwithStyleが悪さしてんのかなーとか疑うが何も起こらず
- ThemeContextをrequireするとちゃんとモックが有効だが、importだと有効にならない!!
- この辺からmock, doMockとかの意味をちゃんと調べて気合いとガッツでtry&Errorしてたらimportでもちゃんとモック化できた!!