LoginSignup
1

Storybook上でインタラクションテストを実行する

Last updated at Posted at 2023-02-14

はじめに

フロントエンド開発においてStorybookを導入しているが、ユーザー操作によるコンポーネントの動作を機械的にテストできていない課題があった。  

Storybookを使って、コンポーネントの動作をテストできないか調べると@storybook/test-runnerが良さげだった。
この記事は、@storybook/test-runnerを使ったインタラクションテストの実装方法の備忘録。

サンプルコード

今回は曜日を選択するとメッセージが表示されるVueコンポーネントをサンプルに@storybook/test-runnerでインタラクションテストを書く。

  • サンプル(曜日を選択するとメッセージが表示されるVueコンポーネント)
Sample.vue
<template>
  <div>
    <select v-model="value">
      <option value="" disabled>選択してください</option>
      <option value="Mon">月曜日</option>
      <option value="Tue">火曜日</option>
      <option value="Wed">水曜日</option>
      <option value="Thu">木曜日</option>
      <option value="Fri">金曜日</option>
      <option value="Sat">土曜日</option>
      <option value="Sun">日曜日</option>
    </select>
    <div class="message">
      <div v-if="value === 'Mon'">Monday</div>
      <div v-if="value === 'Tue'">Tuesday</div>
      <div v-if="value === 'Wed'">Wednesday</div>
      <div v-if="value === 'Thu'">Thursday</div>
      <div v-if="value === 'Fri'">Friday</div>
      <div v-if="['Sat', 'Sun'].includes(value)" class="message_holiday">
        土日だワッショイ!!
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
const value = ref('');
</script>

<style lang="scss" scoped>
.message {
  margin-top: 16px;

  &_holiday {
    color: red;
  }
}
</style>

土日を選択すると「土日だワッショイ!!」というメッセージが表示されます。

  • 動作キャプチャ
    • 曜日を選択するとメッセージが表示される

Kapture 2023-01-30 at 16.08.04.gif

ストーリーの追加

サンプルコードのストーリーを追加する。

Sample.stories.js
import Sample from '../Sample.vue';
import { within, userEvent } from '@storybook/testing-library';

const meta = {
  title: 'Components/Sample',
  component: Sample,
  render: () => ({
    components: { Sample },
    template: '<Sample />',
  }),
};

export default meta;

export const Default = {};

このストーリーだけだと、各曜日を選択した際に特定のメッセージが表示されるコンポーネント動作機械的に確認できない

ストーリー上でセレクトボックスを選択して目視での確認が必要。(コンポーネントのpropsの持たせ方を工夫すれば、初期描画時に選択された状態にできそうですが、選択肢の数だけストーリが増えるので面倒ですね。)

Kapture 2023-01-30 at 16.39.15.gif

インタラクションの追加

ここでいうインタラクションとは、ストーリー上でクリックやフォーム入力の操作のことを指す。play関数を定義することで、ストーリー上でのクリックやセレクトボックスの選択が定義できる。

play関数:StorybookのCSF3.0から新機能として追加された関数。

Sample.stories.js
...
...
export const Monday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    // セレクトボックスで月曜日を選択
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Mon');
  },
};

export const Tuesday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Tue');
  },
};

export const Sunday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Sun');
  },
};

上記のインタラクションが定義されたストーリーを追加することで、セレクトボックスが選択された結果の画面が描画される。

Kapture 2023-01-30 at 16.49.13.gif

上記キャプチャでは全ての曜日のストーリーを定義している

インタラクションの操作結果はスナップショットに反映されないため、特定のメッセージが出力されていることを機械的に確認することはできていません。

(本題)@storybook/test-runnerでインタラクションテストを書く

1. 必要なライブラリのインポート

yarn add -D @storybook/test-runner @storybook/jest

2. インタラクションテストの追加

Sample.stories.js
...
...
export const Monday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Mon');
    // 月曜日を選択した場合は「Monday」が表示されること
    await expect(await canvas.queryByText('Monday')).toBeTruthy();
  },
};

export const Tuesday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Tue');
    // 火曜日を選択した場合は「Tuesday」が表示されること
    await expect(await canvas.queryByText('Tuesday')).toBeTruthy();
  },
};

export const Sunday = {
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.selectOptions(canvas.getByRole('combobox'), 'Sun');
    // 日曜日を選択した場合は「土日だワッショイ!!」が表示されること
    await expect(await canvas.queryByText('土日だワッショイ!!')).toBeTruthy();
  },
};

ここでは以下のインタクションテストを追加。

  • 月曜日を選択した場合は Monday が表示されること
  • 火曜日を選択した場合は Tuesday が表示されること
  • 日曜日を選択した場合は 土日だワッショイ!! が表示されること

3. インタラクションテストの実行方法

  • 実行コマンド
# 6006番ポートでStorybookを起動
yarn storybook dev --port 6006

# 起動しているStorybook上でtest-runnerを実行(インタラクションテストの実行)
yarn test-storybook --url http://localhost:6006
  • 実行結果
$ test-storybook --url http://localhost:6006
 PASS   browser: chromium  ../hogehoge/Sample.stories.js
  Components/Sample
    Default
      ✓ smoke-test (27 ms)
    Monday
      ✓ play-test (34 ms)
    Sunday
      ✓ play-test (7 ms)

Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        3.172 s
Ran all test suites.
✨  Done in 5.93s.

テストが全て成功

  • 試しにSample.vueのメッセージ内容を変更してインタクションテストを実行してみる
    • (Sample.stories.jsのメッセージ内容は修正しない)
Sample.vue
(省略...)
  <div>
    <select v-model="value">
      <option value="" disabled>選択してください</option>
      <option value="Mon">月曜日</option>
      <option value="Tue">火曜日</option>
      <option value="Wed">水曜日</option>
      <option value="Thu">木曜日</option>
      <option value="Fri">金曜日</option>
      <option value="Sat">土曜日</option>
      <option value="Sun">日曜日</option>
    </select>
    <div class="message">
      <div v-if="value === 'Mon'">Monday</div>
      <div v-if="value === 'Tue'">Tuesday</div>
      <div v-if="value === 'Wed'">Wednesday</div>
      <div v-if="value === 'Thu'">Thursday</div>
      <div v-if="value === 'Fri'">Friday</div>
      <div v-if="['Sat', 'Sun'].includes(value)" class="message_holiday">
-        土日だワッショイ!!
+        土日だワッチョイ!!
      </div>
    </div>
  </div>
...
  • テスト結果
    • インタラクションテストでは「土日だワッショイ!!」が出力されることを期待しているので、失敗するはず
yarn test-storybook --url http://localhost:6006

$ test-storybook --url http://localhost:6006
 FAIL   browser: chromium  app/frontend/stories/components/Sample.stories.js
  Components/Sample
    Default
      ✓ smoke-test (27 ms)
    Monday
      ✓ play-test (33 ms)
    Sunday
      ✕ play-test (14 ms)

Sunday(日曜日を選択した場合)のテストコードが失敗した。👍

まとめ

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
1