Storybook 및 Vitest와 함께하는 인터랙티브 Angular 컴포넌트 테스트
Source: Dev.to
Storybook은 UI 컴포넌트와 페이지를 격리된 환경에서 구축하기 위한 프런트엔드 워크숍입니다. Storybook을 Vitest와 함께 사용하면 인터랙티브한 컴포넌트 테스트가 가능합니다.
이 가이드는 Vite와 @storybook/addon-vitest 패키지를 사용하여 Angular와 Storybook을 설정하고 인터랙티브 컴포넌트 테스트를 수행하는 방법을 단계별로 안내합니다.
1. Storybook 설정
Storybook이 아직 설정되지 않았다면, Angular 프로젝트용으로 초기화하기 위해 다음 명령을 실행하세요:
npx storybook@latest init --type angular
이 명령은 필요한 Storybook 의존성을 설치하고 예제 컴포넌트(버튼 컴포넌트를 포함)와 함께 Storybook 구성을 생성합니다. 프롬프트에 따라 진행하고 생성된 파일을 커밋하세요.
2. Analog와 함께 Vite를 사용하도록 Storybook 구성하기
Analog용 Angular 통합 설치
npm install @analogjs/storybook-angular @angular/animations zone.js --save-dev
.storybook/main.ts 업데이트
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
angular.json에서 Storybook 대상 조정
{
"storybook": {
"builder": "@analogjs/storybook-angular:start-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
},
"build-storybook": {
"builder": "@analogjs/storybook-angular:build-storybook",
"options": {
"configDir": ".storybook",
"styles": ["src/styles.css"],
"experimentalZoneless": true
}
}
}
설정을 확인하기 위해 Storybook 실행
npm run storybook
Storybook이 예제 컴포넌트와 함께 실행되는 것을 확인할 수 있습니다.
3. 인터랙션 테스트를 위한 Vitest 설정
Vitest 관련 의존성 설치
npm install @analogjs/vitest-angular @storybook/addon-vitest vitest @vitest/browser-playwright --save-dev
.storybook/main.ts에 Vitest 애드온 추가
import { StorybookConfig } from '@analogjs/storybook-angular';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-vitest',
],
framework: {
name: '@analogjs/storybook-angular',
options: {},
},
};
export default config;
Vitest 설정 파일 생성
.storybook/vitest.setup.ts
import '@angular/compiler';
import { setProjectAnnotations } from '@analogjs/storybook-angular/testing';
import { beforeAll } from 'vitest';
import * as projectAnnotations from './preview';
const project = setProjectAnnotations([projectAnnotations]);
beforeAll(project.beforeAll);
Storybook의 TypeScript 설정 업데이트
.storybook/tsconfig.json
{
"extends": "../tsconfig.app.json",
"compilerOptions": {
"types": ["node"],
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"exclude": ["../src/test.ts", "../src/**/*.spec.ts"],
"include": [
"../src/**/*.stories.*",
"./preview.ts",
"./vitest.setup.ts"
],
"files": ["./typings.d.ts"]
}
Vitest 설정 파일 추가
vitest.config.ts
///
import { defineConfig } from 'vite';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
import { playwright } from '@vitest/browser-playwright';
const dirname =
typeof __dirname !== 'undefined'
? __dirname
: path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
test: {
projects: [
{
extends: true,
plugins: [
storybookTest({
configDir: path.join(dirname, '.storybook'),
}),
],
test: {
name: 'storybook',
browser: {
enabled: true,
headless: true,
provider: playwright(),
instances: [{ browser: 'chromium' }],
},
setupFiles: ['.storybook/vitest.setup.ts'],
},
},
],
},
});
Playwright 브라우저 바이너리 설치
npx playwright install chromium
angular.json에 test-storybook 타깃 추가
{
"test-storybook": {
"builder": "@analogjs/vitest-angular:test",
"options": {
"configFile": "vitest.config.ts"
}
}
}
package.json에 스크립트 추가
{
"scripts": {
"test-storybook": "ng run your-app:test-storybook"
}
}
your-app을 실제 Angular 프로젝트 이름으로 교체하세요.
4. 인터랙션 테스트 작성
Storybook의 초기 설정으로 생성된 Button 컴포넌트는 인터랙션 테스트에 적합한 후보입니다. 아래는 Storybook 테스트 유틸리티를 활용하는 play 함수를 추가한 예시입니다.
import type { Meta, StoryObj } from '@storybook/angular';
import { fn, expect, userEvent, within } from '@storybook/test';
import { Button } from './button.component';
const meta: Meta = {
title: 'Example/Button',
component: Button,
argTypes: {
onClick: { action: 'clicked' },
},
};
export default meta;
type Story = StoryObj;
export const Primary: Story = {
args: {
label: 'Button',
primary: true,
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /button/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled();
},
};
npm run test-storybook을 실행하면 Storybook 인스턴스에 대해 인터랙션 테스트가 수행됩니다.
아래는 추가적인 스토리를 포함하고 play 함수를 다양한 시나리오에서 보여주는 보다 확장된 예시입니다.
import type { Meta, StoryObj } from '@storybook/angular';
import { within, userEvent, expect } from '@storybook/testing-library';
import { fn } from '@storybook/addon-actions';
import { Button } from './button.component';
const meta: Meta = {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
args: { onClick: fn() },
};
export default meta;
type Story = StoryObj;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalled();
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /Button/i });
await expect(button).toBeInTheDocument();
await expect(button).toHaveClass('storybook-button--secondary');
},
};
play 함수로 할 수 있는 일
within(canvasElement)를 사용해 요소를 조회userEvent로 사용자 상호작용 시뮬레이션expect로 어설션 수행- 그 외 다양한 기능 …
테스트 실행
인터랙션 테스트를 실행하려면:
npm run test-storybook
이 명령은 play 함수를 테스트로 사용하는 모든 스토리를 실제 브라우저에서 Playwright를 이용해 실행하므로, 컴포넌트가 예상대로 동작하는지 확신할 수 있습니다.
스토리북 UI에서 직접 테스트를 실행할 수도 있습니다:
- 스토리북을 시작합니다.
- 사이드바의 Run Tests 버튼을 사용하거나, 스토리를 열어 Interactions 패널에서 인터랙션 테스트가 자동으로 실행되는 것을 확인합니다.
결론
Angular와 Vite를 사용한 Storybook은 빌드 속도를 높이고 개발자 경험을 향상시킵니다. 상호작용 테스트를 위해 Vitest를 추가하면 스토리에서 직접 컴포넌트 동작을 검증할 수 있습니다.
전체 Storybook 설정이 포함된 예제 리포지토리를 확인하세요.
이 글이 마음에 드셨다면 ❤️를 눌러 다른 사람들이 볼 수 있게 해 주세요. **AnalogJS**와 **저**를 Twitter/X에서 팔로우하고, 더 많은 콘텐츠를 위해 **YouTube 채널**을 구독하세요!