React + Storybook에서 테스트 코드 작성해 보기

이번에 React + Storybook에서 간단히 테스트 코드를 작성하는 방법에 대해서 알아보았습니다.
2024.02.24

이번에 React + Storybook에서 간단히 테스트 코드를 작성하는 방법에 대해서 알아보았습니다.

준비

먼저 React 프로젝트를 생성 후 필요한 라이브러리를 설치합니다.

npm create vite@latest [project-name] -- --template react-ts
npx storybook init --builder @storybook/builder-vite
npm install -D @storybook/test

*이번 테스트 코드 작성에서는 vitest를 기준으로 작성해 보고 싶어 참고 자료와 달리 @storybook/test를 설치해 테스트 코드를 작성하고 있습니다.

Storybook 작성

이번 Storybook 작성에서 React 관련 코드는 스킵 하도록 하겠습니다.

preview.tsx

import type { Preview } from '@storybook/react'
import React from 'react'
import '../src/index.css'

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    layout: 'fullscreen',
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
  decorators: [
    (Story) => {
      return <Story />
    },
  ],
}

export default preview

Page.stories.tsx

import type { Meta, StoryObj } from '@storybook/react'
import { within, expect, userEvent } from '@storybook/test'

import { Page } from './Page'

const meta: Meta<typeof Page> = {
  component: Page,
}
export default meta

type Story = StoryObj<typeof Page>

export const Default: Story = {
  render: (_args) => <Page />,
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement)
    const user = userEvent.setup()

    const email = canvas.getByTestId('email')
    const password = canvas.getByTestId('password')

    await user.type(email, 'email@example.com')
    await user.type(password, 'password')

    expect(canvas.getByTestId('email')).toHaveValue('email@example.com')
    expect(canvas.getByTestId('password')).toHaveValue('password')
  },
}

작성 후 Storybook에서 확인해 보면 아래의 이미지와 같이 테스트 코드의 움직임이 구현 됩니다.

보충

조금더 추가해 계정을 추가하는 기능을 만든다고 가정해 보고 API 와 통합된 테스트 코드도 작성해 보겠습니다.

*API는 실제 API가 아닌 Msw를 이용해 작성해 보았습니다.

Msw 설치

추가로 아래의 라이브러리를 설치합니다.

npm install -D msw
npm install -D msw-storybook-addon

Storybook 작성

위와 같이 React 와 Msw 관련 코드는 스킵 후 빠르게 Storybook 관련 코드만 작성해 보겠습니다.

preview.tsx

import type { Preview } from '@storybook/react'
import React from 'react'
import '../src/index.css'
import { initialize, mswLoader } from 'msw-storybook-addon'

// // Start Mock Service Worker
initialize({ onUnhandledRequest: 'bypass' })

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: '^on[A-Z].*' },
    layout: 'fullscreen',
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
  loaders: [mswLoader],
  decorators: [
    (Story) => {
      return <Story />
    },
  ],
}

export default preview

Page.stories.tsx

...

export const Default: Story = {
  render: (_args) => <Page />,
  parameters: {
    msw: [buildAddUser()],
  },
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement)
    const user = userEvent.setup()

    const email = canvas.getByTestId('email')
    const password = canvas.getByTestId('password')

    await user.type(email, 'email@example.com')
    await user.type(password, 'password')

    expect(canvas.getByTestId('email')).toHaveValue('email@example.com')
    expect(canvas.getByTestId('password')).toHaveValue('password')

    const submit = canvas.getByTestId('submit')
    await user.click(submit)

    // 로딩 표시
    await expect(await canvas.findByText('...loading')).toBeInTheDocument()
    // 성공 상태 확인
    await expect(await canvas.findByText('success')).toBeInTheDocument()
  },
}

작성 후 Storybook에서 다시 확인해 보면 아래와 같이 테스트 코드의 움직임을 확인해 볼 수 있습니다.

이외에도 Msw를 이용하면 error 나 loading 상태의 mock을 쉽게 만들 수 있으므로 추가 테스트 코드를 작성해 보는 것도 좋을 것 같습니다.

참고자료