Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6155e8d
init: server 로직 반영
Yuyeol Aug 23, 2025
8e94485
test: repeatUtils - 매일 반복 케이스 테스트 작성
Yuyeol Aug 23, 2025
e5dba04
feat: repeatUtils - 매일 반복 케이스 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
f9f83de
test: repeatUtils - 주 반복 케이스 테스트 작성
Yuyeol Aug 23, 2025
2812904
feat: repeatUtils - 주 반복 케이스 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
3da4f4e
test: repeatUtils - 월 반복 케이스 테스트 작성
Yuyeol Aug 23, 2025
43c4c8d
feat: repeatUtils - 월 반복 케이스 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
b47eb16
test: repeatUtils - 연 반복 케이스 테스트 작성
Yuyeol Aug 23, 2025
1e96ea7
feat: repeatUtils - 연 반복 케이스 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
b1427d4
test: repeatUtils - 엣지케이스 테스트 작성
Yuyeol Aug 23, 2025
7438580
feat: repeatUtils - 엣지케이스 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
ede6f57
feat: event-list 관련 handlers, handlersUtils 로직 추가
Yuyeol Aug 23, 2025
6e7a8b8
test: useEventOperation - event-list 처리 테스트 작성
Yuyeol Aug 23, 2025
8054fe8
feat: useEventOperation - event-list 처리 테스트 통과 로직 작성
Yuyeol Aug 23, 2025
fa5d3d4
test: repeat ui - 통합테스트 작성
Yuyeol Aug 25, 2025
584d056
feat: repeat ui 주석해제, test 환경에 맞게 속성 설정
Yuyeol Aug 25, 2025
1719c12
test: 반복일정 수정, 제거에 대한 테스트코드 추가 작성, handlersUtils eventMock 분기처리
Yuyeol Aug 25, 2025
9424ae1
test: 캘린더에 반복 아이콘 표시 - 통합테스트 작성
Yuyeol Aug 25, 2025
900ade6
feat: 캘린더에 반복 아이콘 표시 - 로직 추가
Yuyeol Aug 25, 2025
7a0f18d
test: playwright 세팅중
Yuyeol Aug 27, 2025
35eb4d1
test: playwright 세팅
Yuyeol Aug 28, 2025
dc10d3d
test: notifications - e2e 테스트 작성
Yuyeol Aug 28, 2025
df2dbee
test: modal-interaction - e2e 테스트 작성
Yuyeol Aug 28, 2025
fcb6037
test: calendar-view - e2e 테스트 작성
Yuyeol Aug 28, 2025
bd2882d
chore: ci - e2e 추가
Yuyeol Aug 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
name: CI

on:
pull_request_target:
types:
- synchronize
- opened
- reopened

push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
Expand All @@ -28,7 +26,7 @@ jobs:
run: |
pnpm install
pnpm run lint
test:
vitest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -42,7 +40,28 @@ jobs:
with:
node-version: 20
cache: 'pnpm'
- name: test basic
- name: run unit & integration tests
run: |
pnpm install
pnpm run test

e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- uses: pnpm/action-setup@v4
with:
version: latest
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install deps & Playwright browsers
run: |
pnpm install
pnpm run test
pnpm exec playwright install --with-deps
- name: Run E2E tests
run: pnpm run test:e2e
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
.vscode
node_modules
.coverage
test-results/*
101 changes: 101 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

- 당신은 10년차 시니어 프론트엔드개발자로, 그에 대한 경험과 지식을 갖추고있습니다.
- 지시자는 주니어 개발자입니다. 충분히 이해할 만한 쉬운 설명을 하세요.
- 주저하지말고, 최선을 다해서 코딩 선생님의 역할을 수행하세요.
- 모든 질문에 대해 한국어로 답변하세요.
- 다른 곳에서 정보를 찾아보라고 제안하지 마세요.
- 복잡한 문제나 작업을 작은 단위로 나누어 각각의 단계를 논리적으로 설명하세요.
- 질문이 불명확하거나 모호한 경우, 답변하기 전에 정확한 이해를 위해 추가 설명을 요청하세요.
- 답변 생성 과정 중 더 나은 답변이 떠올랐을 때에는, 답변이 기존 답변의 부족함을 인정하고 개선된 답변을 제시해주세요.
- 주석을 달아달라고 요청할 때에만 간결하게 주석을 추가하세요.
- pnpm dev, pnpm build는 정말 필요할때만 허락을 구하고 사용하도록 하세요.
- 불필요한 토큰 소모를 방지하고 간결한 연산과 답변을 제공하세요.
- [important]작업을 수행하기 전에 먼저 문제의 단계를 나눠서 제시하고, 단계별 수정요청을 받았을때 코드수정을 진행하세요.
- [important]손수 하나하나씩 하는데 의의가 있는 공부 목적의 과제 프로젝트입니다. 한꺼번에 많은 테스크를 혼자 진행하는 것이 아니라 사용자가 학습할 수 있도록 지원하는 것이 기본 전제입니다.
- [important]임의로 필요하다고 생각하는 것이 있더라도 지시없이는 코드를 절대로 수정하지 않습니다.
- 모든 날짜는 2025년을 기준으로 테스트합니다.

## Development Commands

### Core Development

- `pnpm dev` - Start development environment with both frontend and backend servers
- `pnpm start` - Start frontend development server only
- `pnpm run server` - Start backend server only
- `pnpm run server:watch` - Start backend server with file watching
- `pnpm build` - Build for production (TypeScript compilation + Vite build)

### Testing

- `pnpm test` - Run tests with Vitest
- `pnpm run test:ui` - Run tests with Vitest UI
- `pnpm run test:coverage` - Run tests with coverage report

### Code Quality

- `pnpm lint` - Run both ESLint and TypeScript checks
- `pnpm run lint:eslint` - Run ESLint only
- `pnpm run lint:tsc` - Run TypeScript type checking only

## Architecture Overview

This is a React-based calendar/event management application built with TypeScript, Material-UI, and Vite.

### Frontend Structure

- **Main Component**: `App.tsx` - Contains the primary calendar interface with three main sections:
- Event creation/editing form (left panel)
- Calendar view with week/month toggle (center)
- Event list with search functionality (right panel)

### Custom Hooks Architecture

The application uses a modular custom hooks approach for state management:

- `useCalendarView` - Manages calendar view state (week/month), current date navigation, and holiday data
- `useEventForm` - Handles event form state, validation, and time error handling
- `useEventOperations` - Manages CRUD operations for events (save, delete, edit)
- `useNotifications` - Handles notification system and alert management
- `useSearch` - Manages event search and filtering functionality

### Utility Functions

- `dateUtils.ts` - Date formatting, week/month calculations, event filtering by day
- `eventOverlap.ts` - Detects scheduling conflicts between events
- `eventUtils.ts` - Event manipulation and processing utilities
- `notificationUtils.ts` - Notification timing and alert logic
- `timeValidation.ts` - Time input validation and error messaging

### Backend

- Simple Express.js server (`server.js`) providing REST API endpoints
- Data persistence using JSON file (`src/__mocks__/response/realEvents.json`)
- Endpoints: GET/POST/PUT/DELETE `/api/events`

### Testing Setup

- **Framework**: Vitest with jsdom environment
- **Testing Library**: React Testing Library
- **Mocking**: MSW (Mock Service Worker) for API mocking
- **Test Structure**:
- `__tests__/hooks/` - Custom hook unit tests
- `__tests__/unit/` - Utility function tests
- `__tests__/medium.integration.spec.tsx` - Integration tests
- **Test Environment**: Fixed system time to '2025-10-01' UTC for consistent test results

### Key Dependencies

- **UI**: Material-UI (@mui/material, @mui/icons-material)
- **Notifications**: notistack for snackbar notifications
- **Animation**: framer-motion
- **State Management**: React hooks (no external state management library)

### Development Notes

- Uses pnpm as package manager
- Vite for build tooling and development server
- Concurrent development setup runs both frontend (port default) and backend (port 3000)
- API proxy configured in Vite to forward `/api/*` requests to backend server
60 changes: 60 additions & 0 deletions docs/mock-handlers-extension.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Mock Handlers 확장 - isRepeat 옵션 추가

## 개요
반복 일정 테스트를 위해 기존 Mock Handler들에 `isRepeat` 옵션을 추가하여 확장했습니다.

## 확장이 필요했던 이유
반복 일정과 일반 일정은 **서로 다른 Mock 데이터**가 필요했습니다:
- **일반 일정**: 개별적인 제목을 가진 서로 다른 일정들
- **반복 일정**: 동일한 제목을 가진 여러 날짜의 일정들

기존 핸들러들이 일반 일정용 데이터만 제공했기 때문에, 반복 일정의 "개별 수정/삭제 시 다른 일정에 영향을 주지 않는다"는 시나리오를 테스트할 수 없었습니다.

## 확장된 Handlers

### setupMockHandlerUpdating
```typescript
// 기존 사용법
setupMockHandlerUpdating() // 일반 일정 2개

// 확장된 사용법
setupMockHandlerUpdating({ isRepeat: true }) // 반복 일정 3개
```

### setupMockHandlerDeletion
```typescript
// 기존 사용법
setupMockHandlerDeletion() // 삭제할 일반 일정 1개

// 확장된 사용법
setupMockHandlerDeletion({ isRepeat: true }) // 반복 일정 3개
```

## 구현 방식
1. **공통 데이터 분리**: `mockRepeatingEvents` 배열을 상단에 선언
2. **조건부 데이터 선택**: `isRepeat` 플래그에 따라 다른 데이터셋 사용
3. **배열 복사**: 테스트 독립성을 위해 `[...mockRepeatingEvents]` 복사본 생성
4. **기본값 설정**: 기존 코드 호환성을 위해 `{ isRepeat = false } = {}` 기본값 제공

## 장점
- **코드 중복 제거**: 핸들러 로직 재사용
- **가독성 향상**: `{ isRepeat: true }` 로 의도 명확
- **확장성**: 향후 다른 옵션 추가 가능
- **호환성**: 기존 테스트 코드 수정 없이 동작

## 사용 예시
```typescript
// 반복 일정 개별 수정 테스트
it('반복으로 생성된 일정 중 하나만 수정해도 나머지는 영향받지 않는다', async () => {
setupMockHandlerUpdating({ isRepeat: true });
// ... 테스트 로직
});

// 반복 일정 개별 삭제 테스트
it('반복으로 생성된 일정 중 하나만 삭제해도 나머지는 영향받지 않는다', async () => {
setupMockHandlerDeletion({ isRepeat: true });
// ... 테스트 로직
});
```

이 확장을 통해 반복 일정의 개별 조작 시나리오를 효과적으로 테스트할 수 있게 되었습니다.
32 changes: 32 additions & 0 deletions docs/repeat-schedule-test-retrospective.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 반복 일정 테스트 구현 회고

## 문제 상황
반복 일정 기능의 개별 수정/삭제 테스트를 작성하면서 `setupMockHandlerUpdating`과 `setupMockHandlerDeletion`에 `{ isRepeat: true }` 옵션을 추가했습니다. 코드 중복을 줄이기 위해 공통 데이터 `mockRepeatingEvents`를 만들어 두 핸들러에서 공유하도록 했습니다.

## 발생한 문제
테스트를 실행하니 두 번째 테스트(`setupMockHandlerDeletion`)에서 예상과 다른 결과가 나왔습니다. 3개 항목이 있어야 하는데 2개만 나오는 상황이 발생했습니다.

## 원인 분석
**객체 참조 공유** 때문이었습니다:
1. 첫 번째 테스트에서 `mockRepeatingEvents` 배열의 데이터를 수정
2. 두 번째 테스트에서 같은 배열 참조를 사용하여 이미 변경된 상태로 시작
3. 테스트 간 독립성이 깨짐

## 해결 방법
각 핸들러에서 **배열 복사본**을 생성하도록 수정:
```typescript
// 문제 코드
const mockEvents: Event[] = isRepeat ? mockRepeatingEvents : [기존데이터]

// 수정 코드
const mockEvents: Event[] = isRepeat ? [...mockRepeatingEvents] : [기존데이터]
```

## 배운 점
- **테스트 독립성**은 기본 중의 기본 - 이번에 깨달았다
- Mock 데이터를 공유할 때도 독립성을 지켜야 한다는 것을 처음 인지했다
- 코드 중복 제거도 중요하지만 테스트의 안정성이 우선
- JavaScript의 객체/배열 참조 특성을 항상 염두에 두기
- 공유 데이터를 사용할 때는 복사본 생성 필수

단순해 보이는 리팩터링이지만 테스트의 핵심 원칙을 다시 한번 상기시켜준 좋은 경험이었습니다. 특히 Mock 데이터 레벨에서도 독립성이 필요하다는 점은 새로운 깨달음이었습니다.
87 changes: 87 additions & 0 deletions docs/stratage/testing-strategy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# 캘린더 프로젝트 테스트 전략 (수정판)

> **현재 131개 테스트로 견고한 테스트 스위트 보유.** E2E 테스트로 브라우저 호환성을 보강한다.

---

## 1. 테스트 피라미드 목표 비율

| 유형 | 목표 비중 | 목적 |
| -------------------- | --------- | ------------------------------------ |
| Unit (훅·유틸리티) | 40 % | 비즈니스 규칙을 빠르게 검증 |
| Integration (플로우) | 40 % | 폼 → 훅 → 상태 → UI 데이터 흐름 보장 |
| **E2E** | **20 %** | 실제 사용자 시나리오 보호 |
| Visual Regression | ✖︎ | 이번 범위에서 제외 |

---

## 2. E2E 테스트 설계

### 2-1 도구

- **Playwright** (멀티 브라우저·모바일·네트워크 시뮬레이션 지원)
- 기존 MSW 핸들러 재사용 → 외부 API 의존 제거

### 2-2 E2E 범위 선택 기준

#### **CRUD 테스트 제외**

- **테스트 독립성 파괴**: 일정 추가/수정/삭제로 인한 상태 변경이 다른 테스트에 영향
- **병렬 실행 불가**: 여러 브라우저가 동일한 JSON 파일 동시 수정시 Race Condition 발생
- **플래키 테스트 위험**: 이전 테스트 실패시 연쇄적 실패, 테스트 순서 의존성 발생
- **통합테스트로 충분**: 131개 테스트로 CRUD 로직은 이미 완벽히 검증됨

#### **비파괴적 테스트 선택**

- **상태 변경 없음**: 기존 데이터만 읽고 UI 동작만 확인
- **브라우저별 차이**: jsdom으로 검증 불가능한 실제 렌더링/동작 확인
- **사용자 경험**: 실제 브라우저 환경에서의 UI 인터랙션 검증

### 2-3 핵심 시나리오 3선 (통합테스트 한계 보완)

#### **E2E-01: 알림 표시**

- **테스트**: `clock.tick(60000)` → 알림 배지/토스트 표시 확인
- **통합 한계**: jsdom에서 실제 타이머 동작, 시각적 알림 표시 확인 불가
- **E2E 가치**: 브라우저별 타이머, 알림 UI 실제 렌더링 검증
- **독립성**: 기존 데이터만 읽음, 상태 변경 없음

#### **E2E-02: 모달 인터랙션**

- **테스트**: 충돌 모달 열기 → ESC로 닫기 → 배경 클릭으로 닫기
- **통합 한계**: 모달의 실제 z-index, 포커스 트랩, 스크롤 차단 확인 불가
- **E2E 가치**: 브라우저별 모달 렌더링 차이 검증
- **독립성**: 모달만 확인, 실제 저장은 취소

#### **E2E-03: 캘린더 뷰 렌더링**

- **테스트**: 주간/월간 뷰 전환 → 날짜 표시 확인
- **통합 한계**: 복잡한 테이블 레이아웃, CSS Grid 실제 렌더링 확인 불가
- **E2E 가치**: 브라우저별 캘린더 표시 차이 검증
- **독립성**: 기존 데이터만 읽음, 뷰 전환만 테스트

---

## 3. 기능별 현재 커버리지 & 잔여 과제

| 기능 영역 | 복잡도 | 현행 단위·통합 커버리지 | 통합테스트 한계 | 필요한 E2E 테스트 |
| ---------------- | ------ | -------------------------------------- | ----------------------------- | ----------------- |
| 실시간 알림 | High | ✅ 훅 단위 완료 \| ✅ 통합 완료 | jsdom 타이머, 시각적 UI 표시 | **E2E-01** |
| 이벤트 충돌 모달 | High | ✅ 단위 (eventOverlap) \| ✅ 통합 완료 | 실제 모달 포커스/z-index | **E2E-02** |
| 캘린더 뷰 렌더링 | Medium | ✅ 통합 완료 | 복잡한 테이블 레이아웃 렌더링 | **E2E-03** |
| 반복 일정 CRUD | High | ✅ 단위 (repeatUtils) \| ✅ 통합 완료 | 없음 (충분히 검증됨) | **제외** |
| 검색 기능 | Medium | ✅ 단위 완료 \| ✅ 통합 완료 | 없음 (충분히 검증됨) | **제외** |

## 5. 작업 계획

1. **E2E 시나리오 3개 구현 (필수)**

- E2E-01 알림 표시 (통합테스트 한계 1순위)
- E2E-02 모달 인터랙션 (포커스/z-index 검증)
- E2E-03 캘린더 뷰 렌더링 (테이블 레이아웃)

2. **후순위 개선(시간 여유 시)**
- 모바일 브라우저 호환성 테스트
- 대량 데이터 처리 성능 테스트
- 네트워크 오류 시나리오 E2E 테스트
- CI 테스트실패 시 스크린샷·비디오 아티팩트 업로드 → 머지 차단
Loading
Loading