이번에 새로운 프로젝트에 참여하게되었다.
짧은 기간이지만, 개발해야할 기능들이 많고 테스트 코드까지 작성해야 하기에 바쁜 나날이 될거같다.
이번 프로젝트에서는 Story Book을 이용해 컴포넌트 UI 테스트를 진행한다.
그렇기에 간단한 지식정도는 알고 진행하는 것이 팀원들에게 대한 예의라 생각한다.
본 글은 Story Book의 공식 문서에 나온 튜토리얼 중 시작부터 Redux를 이용한 상태 관리 까지의 과정을 기록한 글입니다.
1. 스토리 북(Story Book)이란?
UI를 컴포넌트 단위로 테스팅 할 수 있는 툴이다.
컴포넌트 단위로 테스팅 하는 점에서 잘 분리된 컴포넌트를 재사용하는 React와 잘 맞는 UI 테스팅 툴이라 생각한다.
스토리 북을 사용하는 이유는 아래와 같다.
독립적인 환경에서 컴포넌트를 재사용해 그리기 때문에 다른 컴포넌트와 의존성이 낮고, 재사용이 쉬운 컴포넌트 개발이 가능하다. (개발 환경)
만들어진 컴포넌트들을 조합해 스냅샷을 만들어 테스트에 사용할 수 있습니다.(테스팅)
애드온을 통해 상태 관리 혹은 디버깅 도구, 테스트 도구 등을 통합할 수 있다.(확장성)
UI 컴포넌트 라이브러리를 문서화 하고 디자인 시스템 개발 할 수 있다.(문서화)
2. Story Book 세팅
2.1 CRA를 이용한 React 프로젝트에 적용
npx create-react-app storybook-app --template typescript
React가 재대로 설치되었는지 확인한다.
이후 스토리북을 설치하자.
npx -p @storybook/cli sb init
2.2 Webpack으로 구성된 프로젝트에 적용
npx sb init --builder webpack5
위의 명령어로 스토리북을 설치하자.
혹시 dotenv-webpack이 설치되어 있지 않다면 아래의 명령어도 입력해주자.
npm install dotenv-webpack --save-dev
2.3 실행 단계
전부 올바르게 설치되었다면 stories 폴더에 샘플 코드들이 생겼을 것이다.
이후 package.json을 확인하고 아래의 명령어를 입력해 스토리북을 실행해 보자.
npm run storybook
3. 사용
기본적으로 컴포넌트를 이용해 하야하는 툴이기에 컴포넌트를 만들어야 한다.
공식문서의 예시를 가져왔다.
import React from 'react';
import Task from './Task';
export default function TaskList({ loading, tasks, onPinTask, onArchiveTask }) {
const events = {
onPinTask,
onArchiveTask,
};
const LoadingRow = (
<div className="loading-item">
<span className="glow-checkbox" />
<span className="glow-text">
<span>Loading</span> <span>cool</span> <span>state</span>
</span>
</div>
);
if (loading) {
return (
<div className="list-items" data-testid="loading" key={"loading"}>
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
{LoadingRow}
</div>
);
}
if (tasks.length === 0) {
return (
<div className="list-items" key={"empty"} data-testid="empty">
<div className="wrapper-message">
<span className="icon-check" />
<div className="title-message">You have no tasks</div>
<div className="subtitle-message">Sit back and relax</div>
</div>
</div>
);
}
const tasksInOrder = [
...tasks.filter((t) => t.state === "TASK_PINNED"),
...tasks.filter((t) => t.state !== "TASK_PINNED"),
];
return (
<div className="list-items">
{tasksInOrder.map((task) => (
<Task key={task.id} task={task} {...events} />
))}
</div>
);
}
TaskList 라는 컴포넌트가 있다.
이 컴포넌트는 여러개의 Task 컴포넌트를 갖을 수 있는 컴포넌트이다.
이제 stories 파일을 생성해 보자.
import React from 'react';
import TaskList from './TaskList';
import * as TaskStories from './Task.stories';
export default {
component: TaskList,
title: 'TaskList',
decorators: [story => <div style={{ padding: '3rem' }}>{story()}</div>],
};
const Template = args => <TaskList {...args} />;
export const Default = Template.bind({});
Default.args = {
// Shaping the stories through args composition.
// The data was inherited from the Default story in Task.stories.js.
tasks: [
{ ...TaskStories.Default.args.task, id: '1', title: 'Task 1' },
{ ...TaskStories.Default.args.task, id: '2', title: 'Task 2' },
{ ...TaskStories.Default.args.task, id: '3', title: 'Task 3' },
{ ...TaskStories.Default.args.task, id: '4', title: 'Task 4' },
{ ...TaskStories.Default.args.task, id: '5', title: 'Task 5' },
{ ...TaskStories.Default.args.task, id: '6', title: 'Task 6' },
],
};
export const WithPinnedTasks = Template.bind({});
WithPinnedTasks.args = {
// Shaping the stories through args composition.
// Inherited data coming from the Default story.
tasks: [
...Default.args.tasks.slice(0, 5),
{ id: '6', title: 'Task 6 (pinned)', state: 'TASK_PINNED' },
],
};
export const Loading = Template.bind({});
Loading.args = {
tasks: [],
loading: true,
};
export const Empty = Template.bind({});
Empty.args = {
// Shaping the stories through args composition.
// Inherited data coming from the Loading story.
...Loading.args,
loading: false,
};
stories 파일에서 args로 해당 컴포넌트로 전달되는 초기 인수를 전달할 수 있다.
또한 decorator를 이용해 스토리북에서 컴포넌트가 보여질때 스타일을 지정할 수 있고,
컴포넌트로 컨텍스트를 제공할 수 있다.
Parameters를 이용해 컴포넌트에 대한 메타데이터를 정의하는 데 사용된다.
주로 추가적인 설정, 레이아웃 변경, 애드온 설정 등을 수행한다.
export default {
title: 'Button',
component: Button,
parameters: {
docs: {
description: {
component: 'A customizable button component.',
},
},
},
};
컨텍스트를 전달하는 예시는 링크를 확인하자.
추가적인 애드온 설치는 링크를 확인하자
참고 링크
'FE 이모저모 공부' 카테고리의 다른 글
Testing-library를 이용해 React 컴포넌트 테스팅 (0) | 2024.01.12 |
---|---|
Emotion 가볍게 공부하기 (0) | 2024.01.05 |
CSS 애니메이션과 JS 애니메이션 (0) | 2023.09.09 |
CI/CD 파이프라인 (0) | 2023.09.07 |
모듈 번들러와 트랜스파일러 (0) | 2023.09.07 |