
버튼 하나 고치려고 로그인부터 다시 해야 하나요? (Storybook의 필요성)
복잡한 페이지 깊숙이 있는 컴포넌트를 수정할 때마다 로그인을 다시 하고 클릭을 5번 해야 하나요? Storybook으로 컴포넌트를 격리(Isolation)해서 개발하는 CDD 방법론.

복잡한 페이지 깊숙이 있는 컴포넌트를 수정할 때마다 로그인을 다시 하고 클릭을 5번 해야 하나요? Storybook으로 컴포넌트를 격리(Isolation)해서 개발하는 CDD 방법론.
코드를 먼저 짜고 테스트하는 게 아닙니다. 테스트를 먼저 짜고, 그걸 통과하기 위해 코딩하는 것. 순서를 뒤집으면 버그가 사라집니다.

백엔드: 'API 다 만들었어요.' 프론트엔드: '어떻게 써요?' 이 지겨운 대화를 끝내주는 Swagger(OpenAPI)의 마법.

코드 푸시하면 로봇이 테스트하고(CI), 로봇이 배포합니다(CD). '내 컴퓨터에서는 잘 됐는데'라는 변명은 이제 안 통합니다. 자동화 파이프라인으로 하루 100번 배포하기.

유닛 테스트가 다 통과해도 배포하면 에러가 나는 이유는 뭘까요? 사용자가 실제로 사용하는 흐름 그대로를 검증하는 E2E(End-to-End) 테스트가 필요합니다. Cypress와 Playwright의 장단점 비교, 깨지기 쉬운(Flaky) 테스트를 방지하는 전략, 그리고 테스트 피라미드 속 E2E의 역할을 정리합니다.

결제 실패 모달(PaymentErrorModal)의 디자인을 수정해야 했습니다.
그런데 이 모달을 보려면...
CSS 한 줄 고치고 저장할 때마다 이 짓을 반복해야 했습니다. "아, 그냥 모달만 따로 떼서 보고 싶다!"
저는 Storybook이 "디자이너를 위한 예쁜 문서 만드는 도구"인 줄 알았습니다. "우린 스타트업이라 문서 관리할 시간 없어. 바빠 죽겠는데 무슨 스토리북이야."
하지만 Storybook의 진가는 문서화가 아니라 "개발 속도 향상(Development Velocity)"에 있습니다. 앱 전체를 실행하지 않고, 컴포넌트 하나만 똑 떼어내서(Isolation) 독립적으로 개발할 수 있게 해주는 "컴포넌트 실험실"입니다.
이걸 "자동차 조립"에 비유하니 이해가 됐습니다.
PaymentErrorModal을 스토리북에 등록하면, 브라우저 켜자마자 모달이 떠 있습니다.
로그인도, 결제 시도도 필요 없습니다.
그냥 CSS 고치면 0.1초 만에 반영됩니다.
Button.tsx 옆에 Button.stories.tsx를 만듭니다.
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
title: 'Common/Button',
};
export default meta;
type Story = StoryObj<typeof Button>;
// 기본 상태
export const Default: Story = {
args: {
label: 'Click Me',
variant: 'primary',
},
};
// 에러 상태 (이거 보려고 로그인 안 해도 됨!)
export const Error: Story = {
args: {
label: 'Error',
variant: 'danger',
},
};
스토리북 UI에서 variant를 드롭다운으로 바꾸거나, label 텍스트를 실시간으로 수정할 수 있습니다.
디자이너한테 "이거 폰트 크기 16px로 하면 어때요?"라고 물어볼 필요 없이,
스토리북 링크 던져주고 "직접 조절해 보세요"라고 하면 됩니다. 커뮤니케이션 비용이 0이 됩니다.
"이름이 100글자면 버튼이 깨지나요?"
실제 앱에서는 이름 100글자 넣어서 가입하기 힘들지만,
스토리북에서는 args에 100글자 붙여넣으면 1초 만에 확인 가능합니다.
export const LongText: Story = {
args: {
label: 'Super Long Text Super Long Text Super Long Text...',
},
};
"API 호출하는 컴포넌트는요?"
msw-storybook-addon을 쓰면 네트워킹도 가로채서(Mocking) 가짜 응답을 줄 수 있습니다.
// UserProfile.stories.tsx
export const Success: Story = {
parameters: {
msw: {
handlers: [
http.get('/api/user', () => {
return HttpResponse.json({ name: 'Batman' });
}),
],
},
},
};
이제 백엔드 서버가 죽어있어도 프론트엔드 개발은 멈추지 않습니다.
Storybook은 단순히 "보여주는" 것을 넘어 "동작"을 테스트할 수 있습니다.
play 함수를 사용하면, 사용자의 클릭/입력을 시뮬레이션할 수 있습니다. (Jest + Testing Library 내장)
import { userEvent, within } from '@storybook/testing-library';
export const SubmitForm: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// 1. 이메일 입력
await userEvent.type(canvas.getByLabelText('Email'), 'test@example.com');
// 2. 비밀번호 입력
await userEvent.type(canvas.getByLabelText('Password'), '1234');
// 3. 로그인 버튼 클릭
await userEvent.click(canvas.getByRole('button'));
// 4. 성공 메시지 확인
await expect(canvas.getByText('Welcome!')).toBeInTheDocument();
},
};
이렇게 하면 스토리북을 킬 때마다 자동으로 폼을 채우고 제출하는 시나리오가 실행됩니다. QA 팀에게 넘기기 전에 개발자가 스스로 기능 검증을 끝낼 수 있습니다.
storybook-addon-a11y를 설치하면, 내 컴포넌트가 웹 접근성 표준(WCAG)을 지키는지 자동으로 검사해줍니다.
이런 실수를 배포 전에 잡아낼 수 있습니다. 접근성은 나중에 고치려면 지옥이지만, 처음부터 챙기면 습관이 됩니다.
디자이너가 Figma에서 작업한 디자인을 Storybook 패널 옆에 띄울 수 있습니다.
storybook-addon-designs를 쓰면 됩니다.
개발자는 코드를 짜면서, 바로 옆 탭에서 "디자인 시안"을 픽셀 단위로 비교할 수 있습니다. "디자인이랑 다른데요?"라는 말을 들을 확률이 현저히 줄어듭니다.