storybook은 작성한 리액트 컴포넌트를 독립적으로 개발하고, 관리하고 테스팅하며, 문서화 할 수 있게 해줍니다.
쉽게 생각하면 현재 작성하고 있는 프로젝트의 Button 컴포넌트를 부트스트랩 공식 문서처럼 누구나 컴포넌트의 코드, 외형을 파악하고 문서화해서 관리하게 해줍니다. 때문에 협업에서 뛰어난 효율성을 가집니다.
아쉬운 점은 높은 러닝 커브와 모듈이 자주 충돌하는 번잡한 환경 설정이 있었습니다.
최신 버전에는 Interaction Tests로 실제로 테스팅 과정에서 개발자가 직접 button을 누르거나 input을 입력하면서 테스팅할 필요가 없이 jest, testing-library 함수를 자동으로 상호작용해서 테스팅해줍니다.
예전에는 콘솔로만 확인했던 테스트가 아닌 화면에 상호작용해주면서 직접 눈으로 확인할 수 있는 장점이 있습니다.
Storybook이 그래서 구체적으로 무엇인지 헷갈리실 수 있습니다. 저 역시 처음 접할 때는 "그래서 이걸로 뭘 하려하는 것일까?" 라고 생각해보기도 했습니다. 이번 글을 읽어보시며 생각이 정리되셨으면 좋겠습니다.
* 현재 글의 스타일링에서 Tailwind CSS를 사용하지만 필수 사항이 아닙니다.
Storybook 환경 구성
먼저 Storybook을 설치해보겠습니다.
npx storybook@latest init
Storybook을 적용하고 싶으신 프로젝트 루트에서 위 명령어를 실행해주세요.
그 다음, Storybook에서 테스팅을 하기 위해 addon을 설치하겠습니다.
yarn add -D @storybook/jest @storybook/testing-library
아래 명령어로 Storybook을 실행하게 됩니다. 프로젝트를 localhost:3000으로 실행하는 것과 달리 localhost:6006인 다른 로컬 서버로 실행하게 됩니다.
yarn storybook
Storybook 코드 작성
이제 Storybook 코드를 작성해보겠습니다. 밑의 설명에서 차근차근 알아보도록 하겠습니다.
// index.tsx
interface ISelectProps {
data: string[];
onChange?: (e: React.ChangeEvent<HTMLSelectElement>) => void;
}
const Select: React.FunctionComponent<ISelectProps> = ({ data, onChange }) => {
return (
<div className="inline-block">
<select
className="outline-0 w-52 text-sm bg-slate-200 dark:bg-slate-700 py-2.5 px-2 rounded-sm"
name="select"
id="select"
data-testid="select"
onChange={onChange}
>
{data &&
data.map((value, index) => {
return (
<option key={index} value={value}>
{value}
</option>
);
})}
</select>
</div>
);
};
export default Select;
// lib/categories.ts
/* select의 props인 data로 쓰일 문자열 배열입니다. */
export const categories = [
"카테고리를 선택해주세요",
"식품",
"의류",
"가구",
"전자제품",
"화장품",
"소프트웨어",
"도서",
"상품권",
"생활용품",
"기타",
];
// select.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { within, userEvent } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
import Select from "./index";
import { categories } from "../../lib/categories";
const meta: Meta<typeof Select> = {
title: "design system/common/Select",
component: Select,
parameters: {
componentSubtitle: "여러 분류 중에서 하나를 선택할 수 있는 요소입니다.",
},
argTypes: {
data: {
description: "Select의 option 값입니다.",
defaultValue: "카테고리를 선택해주세요",
table: {
type: { summary: "string[]" },
defaultValue: { summary: "카테고리를 선택해주세요" },
},
},
onChange: {
description: "Select의 값이 변경될 때 실행되는 함수입니다.",
table: {
type: { summary: "function" },
defaultValue: {
summary: "(e: React.ChangeEvent<HTMLSelectElement>) => void",
},
},
},
},
};
export default meta;
type Story = StoryObj<typeof Select>;
export const Categories: Story = {
args: {
data: categories,
onChange: () => {},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const selectEl = canvas.getByTestId("select") as HTMLSelectElement;
await userEvent.selectOptions(selectEl, "의류");
expect(selectEl.value).toBe("의류");
},
};
meta
const로 선언된 meta 객체는 컴포넌트를 문서화하기 위해 설명해주기 위해서 작성합니다.
title은 Storybook의 디렉토리 경로를 지정해줍니다.
이미지를 보시면 Select의 Docs가 title로 선언해주었던 "design system/common/Select" 경로에 위치하고 있습니다.
DESIGN SYSTEM 위의 EXAMPLE 항목은 Story 설치 시 기본으로 설치되는 컴포넌트들입니다.
프로젝트 루트의 .storybook에 위치하고 있으며 제거하셔도 무방합니다.
실행된 Storybook의 왼쪽 네비게이션에서 Docs를 눌러보겠습니다.
화면을 보시면 저희가 작성한 코드의 컴포넌트가 렌더링 되어 있으며, 밑에는 코드의 설명이 작성되어 있습니다.
위 코드의 meta 객체와 이미지를 비교해보면 이해가 더 쉽습니다.
Component는 저희가 작성했던 Select 컴포넌트입니다.
Parameters는 메타데이터를 작성할 때 쓰입니다. meta 객체가 아닌 Story를 작성할 때 쓰이는 Parameters와는 개념이 다릅니다.
argTypes는 우리가 작성한 컴포넌트의 Props 같은 기능들을 설명할 때 쓰입니다.
Story
이제 Categories Story를 살펴보겠습니다.
실행된 Storybook의 왼쪽 네비게이션에서 Categories를 클릭해보겠습니다.
왼쪽 네비게이션에서 Selct Docs 밑에 Categories라는 항목이 생긴 이유는 저희가 작성했던 Story에 Categories 객체를 작성했기 때문입니다.
위 코드에서 작성했던 Categories Stroy 객체의 테스팅이 실행된 것을 확인하실 수 있습니다.
args 코드는 Storybook이나 addons에서 변경하거나 제공할 수 있는 동적 데이터로써 제 경우에는 data props를 제공해주었습니다.
play 코드는 Story가 렌더링 된 후에 실행되는 함수를 작성하는 것에 쓰입니다. 보통 테스팅을 할 때 많이 쓰입니다.
기존의 Testing-library와 다르게 Storybook 공식 문서에서는 화면을 테스팅 할 때 아래 코드처럼 canvasElement를 권장합니다.
const canvas = within(canvasElement);
Categories Story를 확인해보시면 play에 작성했던 테스팅처럼 의류가 자동으로 선택된 것을 확인하실 수 있습니다.
Storybook 스스로 테스팅을 실행해주고 저희는 컴포넌트를 시각적으로 확인이 가능하기 때문에 생산성이 크게 증가하게 됩니다.
마치며
오늘은 Storybook의 기초적인 개념에 대해서 알아보았습니다.
사실 이 글에서 설명한 내용은 빙산의 일각이며 Storybook은 훨씬 더 많은 기능들을 제공합니다.
글의 내용 외에 다른 내용이 궁금하시다면 공식 문서를 확인하시는 것을 추천합니다.
'Development > React' 카테고리의 다른 글
Next.js) Tailwind CSS 다크 모드 적용하기 (0) | 2023.05.02 |
---|---|
Styled Components ttf 폰트 적용 문제 해결 (0) | 2023.01.30 |
React Query 테스팅하기(@tanstack/react-query) (0) | 2023.01.16 |
Next.js) msw로 백엔드 Mocking 해보기 (0) | 2023.01.12 |
Next.js)@testing-library로 컴포넌트 테스팅하기 (0) | 2023.01.11 |