storybook을 잘 활용하는 방법

jh·2024년 11월 23일

디자인 시스템

목록 보기
11/14

참고자료
sb test sneak peak
sb 8.4 update

  • storybook 기능에 대한 자세한 설명보다는, 저처럼 storybook에 선입견을 가지신 분들에게 소개하고 싶어 작성했습니다
  • 8.4버전 기준입니다(저는 8.5 alpha버전 사용중입니다)
  • 일부 기능은 실험버전입니다

기존에는 Storybook의 이미지가 그닥 좋지 않았다

  1. 느림
  2. 파일 작성할 때 기본적으로 해야 할 게 많음
  3. 세팅하기 귀찮음

이런 이유로 잘 사용하지 않고 있다가, 디자인 시스템을 만들면서 따로 문서화하는 것보다 Storybook을 활용하는 게 더 좋을 것 같아서 적극적으로 사용해봤는데 생각이 180도 바뀌었다. 아직도 나처럼 생각하는 사람들이 있을 것 같아서 한번 정리해봤다.

Storybook의 단점 개선

  1. 느림
    최근 8.4버전으로 올라오면서 번들 사이즈가 50% 감소했다. 실제로 사용해보니까 초기 로딩 속도가 확실히 빨라진 게 체감된다.

  2. 파일 작성이 귀찮은 문제

  • 정해진 방식대로 작성해야 하는데 기억 안 나서 다른 파일 보면서 복붙해야 됨
  • 컴포넌트 argTypes 일일이 작성하기 (타입 자동완성도 안 되고 컴포넌트 보면서 일일이 옮겨야 됨)
  • 예시 컴포넌트 작성하기

내가 개선한 방법:

  1. plop으로 템플릿 만들어서 해결
  2. react-docgen-typescript로 컴포넌트 prop 자동 파싱 (단, 외부 라이브러리 타입이나 복잡한 경우엔 효과 별로)
  3. 예시 컴포넌트는 어쩔 수 없이 해야 함

StorybookGPT라는 것도 있어서 예시 작성할 때 참고하면 훨씬 편하다.

Storybook으로 테스트하기 - test runner

가장 잘 쓰고 있는 기능으로, Storybook의 test addon을 통해 다양한 UI 테스트가 가능하다

  • axe로 접근성 테스트
  • 컴포넌트 테스트
  • chromatic으로 비주얼 테스트

jest와 playwright 기반의 test-runner를 쓰는데

import { expect, fn, userEvent, within } from "@storybook/test"
import { Button } from "../components"
import type { Meta, StoryObj } from "@storybook/react"
export default {
  title: "Button",
  component: Button,
  tags: ["autodocs"],
} satisfies Meta<typeof Button>

type Story = StoryObj<typeof Button>

export const Primary: Story = {
  args: {
    children: "click",
    onClick: fn(),
  },
  play: async ({ args, canvasElement }) => {
    const canvas = within(canvasElement)
    const button = canvas.getByRole("button")
    await userEvent.click(button)
    await expect(args.onClick).toHaveBeenCalled()
  },
}

export const Text: Story = {
  args: {
    children: "click",
    variant: "text",
  },
}

export const Disabled: Story = {
  args: {
    disabled: true,
    children: "disabled",
    onClick: fn(),
  },
  play: async ({ args, canvasElement }) => {
    const canvas = within(canvasElement)
    const button = canvas.getByRole("button")
    await userEvent.click(button)
    await expect(args.onClick).not.toHaveBeenCalled()
  },
}

여기서 가장 좋았던 점은 이런 식으로 stories파일 내부에 테스트 로직을 작성할 수도 있고, 더 복잡한 테스트 로직이 필요할 경우에는

import { test, expect } from '@jest/globals';
import { render, screen } from '@testing-library/react';
import { composeStories } from '@storybook/react';
 
import * as stories from './Button.stories';

const { Primary, Secondary } = composeStories(stories);
 
test('stories 재사용하여 테스트 로직 작성가능', () => {
	...
});

composeStories API를 활용하여 재사용도 할 수 있다

vitest를 활용한 테스트

기존의 test-runner는 속도나, 디버깅 측면에서 조금 불편함이 있었는데
storybook 8.4버전부터 test-runner 대신 vitest를 통한 storybook 테스트 기능이 출시되었다(experimental)

cli를 통해 storybook을 설치 시에 vite를 통한

@storybook/experimental-addon-test 이라는 addon을 설치하고, vitest 관련 세팅만 해주면 기존의 test-runner를 통해서가 아닌 vitest를 활용한 테스트가 가능하다
(그렇다고 기존의 테스트 코드를 바꾸거나 할 필요는 없다)

일단 가장 큰 장점은 vitest의 장점을 모두 누릴 수 있는 것이다(속도,디버깅,browser mode 등..)

해당 addon을 설치하면, storybook을 켰을 때 왼쪽에 패널이 하나 뜨는데, 이 패널의 버튼 한번만 누르면 모든 테스트부터 chromatic을 통한 배포까지 한번에 할 수 있게 된다.

또한 테스트 pass/fail 결과를 확인하는 것이 매우 편리해졌다

panel

기존에는 관련된 모든 테스트 및 배포를 github actions를 통해 진행하고 있었는데, 약 4분 정도가 소요되었는데,
현재는 저 버튼 하나만 누르면 약 40초 안에 테스트 및 모든 작업이 끝난다

0개의 댓글