vitest
Vitest 테스트 환경 설정 및 사용 규칙. vitest.config.ts, vi.* API, *.test.ts 파일 구조.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Vitest 테스트 환경 설정 및 사용 규칙. vitest.config.ts, vi.* API, *.test.ts 파일 구조.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
세션 핸드오프. 컨텍스트가 차기 전에 중요 맥락을 progress.md에 문서화하고 새 세션 킥오프 프롬프트를 클립보드에 복사한다. "핸드오프", "세션 정리하고 넘기자", "컨텍스트 정리", "이어갈 준비" 등의 요청에 사용.
MD 파일 또는 텍스트로 작업을 정의하면, 분석 → 디자인 확인 → 구현 → 검증 → 커밋 → PR까지 전체 플로우를 수행한다. "이거 만들어줘", "기능 구현해줘", "작업 시작하자", "이 티켓 진행해줘" 등 코드 작업 착수 발화에 사용.
Claude + OpenAI Codex 협업 스킬. MCP 서버 설정 시에만 사용 가능.
code-forge 상태 대시보드. REFLECT flag, quality 이벤트, notepad/decisions, usage 집계를 한 번에. forge-glow 같은 외부 도구는 --json으로 파싱.
교차 모델 토론. Agent Teams / Codex CLI / self-debate 모드 선택. 설계 결정, 아키텍처 선택 시 활용. "어느 쪽이 나을까", "설계 비교해줘", "토론시켜줘", "교차 검증해줘" 등의 요청에 사용.
화면 단위 E2E 테스트 자동화. Figma/코드 기반 테스트 케이스 도출 → Playwright 코드 생성 → Forge Loop(에스컬레이션 기반 자율 실행). "E2E 돌려줘", "화면 테스트 만들어줘", "이 페이지 자동 테스트" 등의 요청에 사용.
| name | vitest |
| description | Vitest 테스트 환경 설정 및 사용 규칙. vitest.config.ts, vi.* API, *.test.ts 파일 구조. |
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
test: {
globals: true, // describe, it, expect를 전역으로 사용
environment: 'jsdom', // 브라우저 환경 시뮬레이션
setupFiles: ['./src/test/setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
exclude: [
'node_modules/**',
'src/test/**',
'**/*.config.ts',
'**/*.d.ts',
],
},
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
});
// src/test/setup.ts
import '@testing-library/jest-dom';
// 전역 mock 설정 등
src/
├── utils/
│ ├── formatPrice.ts
│ └── __tests__/
│ └── formatPrice.test.ts
├── hooks/
│ ├── useOrderStatus.ts
│ └── __tests__/
│ └── useOrderStatus.test.ts
└── components/
├── OrderCard.tsx
└── __tests__/
└── OrderCard.test.tsx
// utils/__tests__/formatPrice.test.ts
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { formatPrice, formatPriceWithUnit } from '../formatPrice';
describe('formatPrice', () => {
describe('정상 케이스', () => {
it('양수 금액을 천 단위 쉼표로 포맷', () => {
expect(formatPrice(10000)).toBe('10,000');
});
it('소수점 금액 처리', () => {
expect(formatPrice(9999.99)).toBe('9,999.99');
});
});
describe('경계값', () => {
it('0원 처리', () => {
expect(formatPrice(0)).toBe('0');
});
it('1원 처리', () => {
expect(formatPrice(1)).toBe('1');
});
});
describe('에러 케이스', () => {
it('음수 처리', () => {
expect(() => formatPrice(-1000)).toThrow();
});
it('NaN 처리', () => {
expect(formatPrice(NaN)).toBe('0');
});
});
});
import { vi, describe, it, expect } from 'vitest';
describe('useOrderActions', () => {
it('주문 삭제 시 onSuccess 콜백 호출', async () => {
const onSuccess = vi.fn();
const onError = vi.fn();
await deleteOrder('order-1', { onSuccess, onError });
expect(onSuccess).toHaveBeenCalledOnce();
expect(onSuccess).toHaveBeenCalledWith({ id: 'order-1' });
expect(onError).not.toHaveBeenCalled();
});
});
import { vi, describe, it, expect, beforeEach } from 'vitest';
// 모듈 전체 모킹
vi.mock('@/services/order', () => ({
fetchOrders: vi.fn(),
createOrder: vi.fn(),
}));
// 모킹된 함수 import
import { fetchOrders } from '@/services/order';
describe('OrderService', () => {
beforeEach(() => {
vi.clearAllMocks(); // 각 테스트 전 mock 초기화
});
it('주문 목록 조회 성공', async () => {
const mockOrders = [{ id: '1', name: '주문 1' }];
vi.mocked(fetchOrders).mockResolvedValue({ orders: mockOrders, total: 1 });
const result = await getOrderList();
expect(fetchOrders).toHaveBeenCalledOnce();
expect(result.orders).toHaveLength(1);
});
it('조회 실패 시 에러 처리', async () => {
vi.mocked(fetchOrders).mockRejectedValue(new Error('Network error'));
await expect(getOrderList()).rejects.toThrow('Network error');
});
});
import { vi } from 'vitest';
describe('logger', () => {
it('오류 발생 시 console.error 호출', () => {
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
triggerError();
expect(consoleSpy).toHaveBeenCalledWith('Error occurred');
consoleSpy.mockRestore(); // 원래 구현 복원
});
});
import { vi, describe, it, expect, beforeAll, afterAll } from 'vitest';
import { getPeriod } from '../getPeriod';
describe('getPeriod', () => {
beforeAll(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2025-01-15T00:00:00.000Z'));
});
afterAll(() => {
vi.useRealTimers();
});
it('last14Days - 오늘 기준 14일 전부터 오늘까지', () => {
expect(getPeriod('last14Days')).toEqual(['2025-01-01', '2025-01-15']);
});
it('thisMonth - 해당 월 1일부터 말일까지', () => {
expect(getPeriod('thisMonth')).toEqual(['2025-01-01', '2025-01-31']);
});
});
import { vi } from 'vitest';
describe('config', () => {
it('프로덕션 환경 설정', () => {
vi.stubEnv('VITE_ENV', 'production');
vi.stubEnv('VITE_API_URL', 'https://api.example.com');
const config = getConfig();
expect(config.isProd).toBe(true);
expect(config.apiUrl).toBe('https://api.example.com');
vi.unstubAllEnvs(); // 테스트 후 복원
});
});
// components/__tests__/OrderCard.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { OrderCard } from '../OrderCard';
const mockOrder = {
id: '1',
name: '테스트 주문',
status: 'active' as const,
};
describe('OrderCard', () => {
it('주문명 렌더링', () => {
render(<OrderCard order={mockOrder} onSelect={vi.fn()} />);
expect(screen.getByText('테스트 주문')).toBeInTheDocument();
});
it('클릭 시 onSelect 호출', () => {
const onSelect = vi.fn();
render(<OrderCard order={mockOrder} onSelect={onSelect} />);
fireEvent.click(screen.getByRole('button'));
expect(onSelect).toHaveBeenCalledWith('1');
});
});
// hooks/__tests__/useCounter.test.ts
import { describe, it, expect } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { useCounter } from '../useCounter';
describe('useCounter', () => {
it('초기값 반환', () => {
const { result } = renderHook(() => useCounter(0));
expect(result.current.count).toBe(0);
});
it('increment 호출 시 카운트 증가', () => {
const { result } = renderHook(() => useCounter(0));
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
});
# 전체 테스트
yarn test
# watch 모드
yarn test --watch
# 특정 파일
yarn test formatPrice.test.ts
# 커버리지
yarn test --coverage
# UI 모드
yarn test --ui
vitest.config.ts에 globals: true, environment: 'jsdom' 설정?vi.useFakeTimers() + vi.setSystemTime() 사용?vi.clearAllMocks() 또는 vi.restoreAllMocks() 사용?vi.mocked() 로 타입 안전하게 접근?describe 중첩으로 시나리오 그룹화?