핵심 요약
Storybook 9의 Vitest 통합이 정식화되며 story 파일이 그대로 단위 테스트가 된다. play function이 Vitest의 describe/it로 해석되고 watch 모드도 동일 인프라. 사내 모노레포에서 Jest 의존성 제거 + CI 컴포넌트 테스트 시간 4분→1분 20초.
1. 무엇이 바뀌었나
- Storybook 자체 test runner 사라짐 → @storybook/test로 통일
- Vitest browser mode 기본 통합
- CSF 4 — TypeScript 우선, args 추론 강화
- addon 38개 → 12개로 정리, lighter
2. 셋업
# 한 줄
npx storybook@9 init
기존 6/7 → 9 마이그레이션은 codemod 제공. addon 변경이 가장 큰 변경점.
3. Story = Test
// Button.stories.tsx
export const Click: Story = {
args: { label: '저장' },
play: async ({ canvas, userEvent, expect }) => {
const btn = canvas.getByRole('button');
await userEvent.click(btn);
expect(btn).toHaveAttribute('data-state', 'loading');
}
};
같은 파일이 시각 카탈로그 + 인터랙션 테스트 + 접근성 점검 모두 담당.
4. CI
# package.json
"test:stories": "vitest --browser=chromium"
GitHub Actions에서 storybook build → vitest 실행. 사내 캐시·병렬 덕분에 1400 stories 1분 20초 완료.
5. 시각 회귀(VRT)
Chromatic 또는 Percy. Storybook 9는 둘 다 지원. 자체 호스팅이라면 storycap + 이미지 diff. 디자인 시스템 PR에서 시각 변경이 즉시 보여 리뷰 시간 절반.
6. 함정
- play function의 import는 반드시 @storybook/test 단일 source — 잘못 import 시 글로벌 jest 객체 누수
- Storybook 8 addon 일부는 9 호환 안 됨 — addon-essentials 분해 후 필요한 것만
7. 다른 도구와 공존
유닛 테스트는 Vitest 단독, 컴포넌트는 Storybook+Vitest, e2e는 Playwright. 사내 표준이 세 갈래가 되지만 각 도구 역할이 명확해 오히려 정리됨.
자주 묻는 질문
Q. Jest 유지하면서 Storybook 9 가능? 가능. 다만 inferiority 큼. 메인테이너 권장은 Vitest 단일화.

댓글 0