📖
StorybookでuseSelectorのモックを追加
Storybook、React初心者です。
Storyook内でuseSelector部分をモックにして表示パターンを作成した時のメモです。
(そもそもStorybookでそんなことするのが適切でないかもしれません。)
前提
- "react": 16.13.1
- "storybook": 5.3.19
- "react-redux": 7.2.0
Fooコンポーネント(一部抜粋)
import * as selectors from "src/selectors"; // Stateのデータを加工してる関数がまとまっている
export const Foo: React.FC<Props> = () => {
...
const something = useSelector(selectors.getSomeState);
...
}
src/selectors(一部抜粋)
import { State } from "src/reducers";
export const getSomeState = (state: State) => state.User.someParametor;
src/reducers(一部抜粋)
// Stateに追加するオブジェクト設定
export type UserState = {
someParametor: {
avator: String;
statuses: [];
}
....
}
Storybookでエラーになった書き方
foo.stories.tsx
const Template = () => <Foo {...args1} />;
export const pettern1 = Template.bind({});
下記のエラーとなり、Storybookで描画できませんでした。
could not find react-redux context value; please ensure the component is wrapped in a <Provider>
コンポーネントを表示させるためだけのダミーのStoreの書き方
表示させるためには<Provider>
でラップする必要があります。
空の<Provider>
を使うことで表示されました。
foo.stories.tsx
import React from "react";
import { Story, Meta } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { Provider } from "react-redux";
import { createStore } from "redux";
import { reducers } from "src/reducers";
import { createBrowserHistory as createHistory } from "history";
import Foo, { Props } from "path/to/file";
// 空のstoreを作成
const dummyStore = createStore(reducers(createHistory()));
// ProviderにStoreを接続してコンポーネントをラップ
const Template: Story<Props> = (args) =>
<Provider store={dummyStore}>
<Foo {...args} />
</Provider >;
const something = useSelector(selectors.getSomeState);
の右になにも入らない状態となります。
実際のStoreのパターンをmockしてパターンを作成する
実際のStoreのパターンを表現できればテストパターンの確認ができます。
参考リンクのReduxを接続の記述が大変役にたちました。お礼申し上げます。
foo.stories.tsx
import React from "react";
import { Provider } from "react-redux";
import { store } from "src/store"; // 定義されたstore
import { UserState } from "src/reducers";
import Foo, { Props } from "path/to/file";
// Storeのmockを作成
// getState()の値に引数のstateをマージすることでStoreの戻り値がカスタマイズできる
const createMock = (state: UserState) => {
return {
...store,
getState: () => {
return { ...store.getState(), ...state };
},
};
};
// Stateのパターン作成
// 取得したいStateの構造と同じ。複製して値をいじることでイレギュラーなケースなどのパターンが作れる
const testStore = createMock({
someParametor: {
avator: "default",
statuses: [],
},
});
// console.log(testStore.getState())でStoreの値は確認できる
// TemplateとsomePatternを対にしてパターンを作成
const Template: Story<Props> = (args) =>
<Provider store={testStore}> // ←パターン別に差し替える
<Foo {...args} />
</Provider >;
export const somePattern = Template.bind({}); //
const something = useSelector(selectors.getSomeState);
にtestStoreの値が代入されます。
作成したパターンはjestにimportすることが可能になります。
制作環境の都合でバージョンが古いためjestへの組み込みは未対応です。
対応可能になったら追記したいと思います。
参考リンク
Discussion