UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【Storybook】play関数とReduxを使ったコンポーネントの組み合わせ

Storybook6.4リリースに伴いplay関数と@testing-library/user-eventで インタラクションの定義を試そうとしたところ、そのコンポーネントがReduxのstoreの値を使うためProviderを利用する必要があるのだが、testing-reactのexampleを探してもplay関数と仮想DOMの両方を定義する方法がわからなかったので調べた

前バージョンStorybookでのProviderを使ったストーリーはこのように書いていた

  const store = ...
  const Template: Story = () => (
    <Provider store={store} key="provider">
      <TranslationProvider initialState={store.getState().app.translation}>
        <TopPage />
      </TranslationProvider>
    </Provider>
  );
  export const EN = Template.bind({});

READMEにあったplay関数の作り方

export const InputFieldFilled: Story<InputFieldProps> = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.type(canvas.getByRole('textbox'), 'Hello world!');
  },
};

これをどう一緒に使うべきか

@testing-reactのREADMEをよくみるとCSF3におけるストーリの作り方の例が以下となっていた

// Example 1: Meta with component property
export default {
  title: 'Button',
  component: Button // <-- This is strictly necessary
}

// Example 2: Story with render method:
export const Primary = {
  render: (args) => <Button {...args}>
}

つまり、renderを使うのがよさそう

ということで以下のように定義したらうまく表示された

export const InputFieldFilled = {
  render: () => (
    <Provider store={store} key="provider">
      <TranslationProvider initialState={store.getState().app.translation}>
        <TopPage />
      </TranslationProvider>
    </Provider>
  ),
  play: async () => {
      await userEvent.type(
        screen.getByTestId("email"),
        "michael@chromatic.com",
      )
  },
};