【Nuxt3】でStorybookを使用して自動テストのテストコードを書く

# はじめに

こんにちは、エンジニアのkeitaMaxです。

今回は前回実装したStorybookを使用して自動テストを書いていきたいと思います。

前回

https://qiita.com/keitaMax/items/8cee088b6edfc0a9266d

# テストライブラリをインストール

https://qiita.com/keitaMax/items/5698eb72106c1fd1397b

Next.jsでインストールしたライブラリを以下のコマンドでインストールします。

```
npm i @storybook/testing-library
npm i @storybook/jest
```
    

# ボタンがあるかどうかをテストする

まずは前回作成したカウントアップ画面のプラスボタンとマイナスボタンがあるかどうかのテストコードを作成します。

index.stories.tsをいかのように修正します。

```ts:index.stories.ts
import { expect } from '@storybook/test';
import { screen } from '@storybook/testing-library';
import CountView from './index.vue';

export default {
  title: 'Views/CountView',
  component: CountView,
  parameters: {
    layout: 'fullscreen',
  },
};
export const Default = {
  render: () => ({
    components: {
      CountView,
    },
    template: '<CountView />',
  }),
  play: async ({ canvasElement }: any) => {
    const incButton = await screen.findByTestId('inc-button');
    expect(incButton);
    const decButton = await screen.findByTestId('dec-button');
    expect(decButton);
  },
};
```

`index.vue`のプラスボタンとマイナスボタンを識別できるようにTestIDを付けます。

`index.vue`を以下のように修正します。

```vue:index.vue
<script setup lang="ts">
  import { useCounter } from './hooks';

  const { counter, inc, dec } = useCounter();
</script>

<template>
  <div class="bg-red-600">
    カウンター: {{ counter }}
    <button data-testid="inc-button" @click="inc">+</button>
    <button data-testid="dec-button" @click="dec">-</button>
  </div>
</template>
```

この状態で以下のコマンドでStorybookを起動します。

```
npm run storybook
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/2f900083-0f14-3f24-2f3d-b012ff3ccc40.png)

するとStorybookの画面下の`Interaction`タブでテストが実行され、成功しているのがわかります。

# 失敗させてみる

次は先ほど成功してテストを失敗させてみます。

index.stories.tsをいかのように修正します。

```ts:index.stories.ts
import { expect } from '@storybook/test';
import { screen } from '@storybook/testing-library';
import CountView from './index.vue';

export default {
  title: 'Views/CountView',
  component: CountView,
  parameters: {
    layout: 'fullscreen',
  },
};
export const Default = {
  render: () => ({
    components: {
      CountView,
    },
    template: '<CountView />',
  }),
  play: async ({ canvasElement }: any) => {
    const incButton = await screen.findByTestId('inc-button');
    expect(incButton);
    const decButton = await screen.findByTestId('dec-button');
    expect(decButton);
    const xxxButton = await screen.findByTestId('xxx-button'); //追加
    expect(xxxButton); //追加
  },
};
```

これでStorybookを起動させると以下のように失敗しているのがわかります。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/f74506d8-3d74-c9e2-c33d-963efc421026.png)

これでテストが正しく動いているのを確認できました。


# ボタンクリックしたときの処理のチェック 

最後にボタンを押したときのチェックをしたいと思います。

以下３つのテストを書いていきます。
・最初に表示されているカウントが０であること
・プラスボタンを押したときにカウントが１になること
・次にマイナスボタンを押したときにカウントが０に戻ること

index.stories.tsをいかのように修正します。
```ts:index.stories.ts
import { expect } from '@storybook/jest';
import { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';// ここを修正
import { CountView } from '.';


const meta: Meta<typeof CountView> = {
  title: 'views/CountView',
  component: CountView,
  tags: ['autodocs'],
}
export default meta

type Story = StoryObj<typeof meta>

export const Test: Story = {
  play: async ({ canvasElement }) => {
    const button = await within(canvasElement).findByTestId('button');
    expect(button).toBeInTheDocument();

    expect(screen.queryByTestId('count-text')?.innerHTML).toBe('0'); // ここを追加
    await userEvent.click(incButton);
    expect(screen.queryByTestId('count-text')?.innerHTML).toBe('1'); // ここを追加
    await userEvent.click(decButton);
    expect(screen.queryByTestId('count-text')?.innerHTML).toBe('0'); // ここを追加
  },
};
```

`index.vue`のテキストを表示している部分を識別できるようにTestIDを付けます。

`index.vue`を以下のように修正します。

```vue:index.vue
<script setup lang="ts">
  import { useCounter } from './hooks';

  const { counter, inc, dec } = useCounter();
</script>

<template>
  <div class="bg-red-600">
    カウンター:
    <p data-testid="count-text">{{ counter }}</p> //追加
    <button data-testid="inc-button" @click="inc">+</button>
    <button data-testid="dec-button" @click="dec">-</button>
  </div>
</template>
```

これでStorybookを起動させると、以下のようにすべてのテストが成功しているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/aadb11a7-64e1-4b40-b5b7-629b7362c31f.png)

# さいごに

Storybookを使用すると簡単に自動テストが作成できました。

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！