N-LAB

Nuxt 3 × Storybook 8 × Vitestでインタラクションテストを実行する

投稿日: 2024年12月28日


目標

※この記事ではフレームワークはNuxt.jsを使用しています。

条件

https://n-laboratory.jp/articles/nuxt3-storybook8

https://n-laboratory.jp/articles/nuxt3-vitest-unittest



・Nuxt.js: 3.15.0
・Storybook: 8.4.7
・Vitest: 2.1.8

目次

  1. パッケージのインストールとセットアップ
  2. インタラクションテストの実行
  3. ブラウザ確認


パッケージのインストールとセットアップ

1. 以下のコマンドを実行します。 @storybook/experimental-addon-testは必要なパッケージのインストール、セットアップを自動で行います。

npx storybook add @storybook/experimental-addon-test


2. Nuxtの自動インポートをインタラクションテストでも有効にするための必要なライブラリをインストールします。不要な場合は読み飛ばしてください。

$ npm install --save-dev unplugin-auto-import unplugin-vue-components

※Nuxtで自動インポートされるrefなどの関数やcomponentsディレクトリに存在するコンポーネントがVitestでは自動インポートされません。以下のライブラリをインストールすると自動インポートした状態でテストが実行できるようになるため、ここではあわせてインストールしています。
・unplugin-auto-import
・unplugin-vue-components

3. ルート配下に vitest.workspace.ts が新規作成されていることを確認します。Nuxtの自動インポートをインタラクションテストでも有効にするため vitest.workspace.ts に以下を追記して保存します。手順2を読み飛ばした場合はこちらも読み飛ばしてください。

// vitest.workspace.ts
import AutoImportFunctions from 'unplugin-auto-import/vite'
import AutoImportComponents from 'unplugin-vue-components/vite'

export default defineWorkspace([
  'vitest.config.ts',
  {
    extends: 'vite.config.ts',
    plugins: [
      storybookTest({ configDir: '.storybook' }),
      storybookVuePlugin(),
      // 以下を追加します。
      AutoImportFunctions ({ imports: [
        'vue',
        'vee-validate',
        'vue-router',
        'pinia',
      ], dts: '.storybook/auto-imports.d.ts',
      }),
      // 以下を追加します。
      AutoImportComponents({
        dirs: ['components'],
        dts: '.storybook/components.d.ts',
      }),
    ],

vitest.workspace.ts はVitestのワークスペース機能を利用しています。1つのプロジェクト内で複数のvitestの設定を使い分けることができます。
今回作成された vitest.workspace.ts はStorybookのインタラクションテスト用の設定ファイルです。

4. package.json に以下のスクリプトを追加します。

"scripts": {
  "test:storybook": "vitest --project=storybook",
},

※オプションに --project=storybook を指定することで *.stories.ts ファイルのみをテスト対象とすることができます。

インタラクションテストの実行

1. componentsディレクトリに Button.vue を新規作成して以下の内容で保存します。

// components/Button.vue
<template>
  <button>ボタン</button>
</template>


2. pagesディレクトリに index.vue を新規作成して以下の内容で保存します。

// pages/index.vue
<script lang="ts" setup>
const isClicked = ref(false)
const handleClick = () => {
  isClicked.value = true
}
</script>
<template>
  <Button @click="handleClick" />
  <p v-if="isClicked">
    Clicked!
  </p>
</template>


3. pagesディレクトリに index.stories.ts を新規作成して以下の内容で保存します。

// pages/index.stories.ts
import type { Meta, StoryObj } from '@storybook/vue3'
import Index from './index.vue'
import { within, userEvent, expect } from '@storybook/test'

type Story = StoryObj<typeof Index>
const meta: Meta<typeof Index> = {
  title: 'Index',
}

export const ClickButton: Story = {
  render: () => ({
    components: { Index },
    template: '<Index />',
  }),
  // インタラクションテストの実装
  play: async ({ canvasElement }) => {
    // Arrange
    const canvas = within(canvasElement)

    // Act
    await userEvent.click(canvas.getByText('ボタン'))

    // Assert
    await expect(canvas.getByText('Clicked!')).toBeInTheDocument()
  },
}

export default meta


4. テストを実行します。テストが成功していることを確認します。

$ npm run test:storybook
> test:storybook
> vitest --project=storybook
 ✓ |storybook| src/pages/index.stories.ts (1)
   ✓ Click Button
 Test Files  1 passed (1)
      Tests  1 passed (1)

※同プロジェクトですでにユニットテストが実装さている場合は、既存のユニットテストが1件も実行されていないことも併せてご確認ください。

ブラウザ確認


1. Storybookを起動します。

$ npm run storybook


2. 該当のストーリを表示します。Component testsタブを選択すると、テストの行単位でどのような操作が行われたかを確認することができます。
storybook test
※ここではhttp://localhost:6006/?path=/story/index--click-buttonにアクセスしています。

以上で全ての手順は完了になります