1+ import { describe , test , expect } from 'vitest' ;
2+
3+ import { Event , EventForm } from '../../types' ;
4+ import { createRepeatEvents , updateSingleRepeatEvent , deleteSingleRepeatEvent , markRepeatEvents } from '../../utils/dateUtils' ;
5+
6+ describe ( '반복 일정 분할 생성' , ( ) => {
7+ test ( '반복 설정이 있는 이벤트는 여러 개의 개별 이벤트로 생성된다' , ( ) => {
8+ // Given: 매월 반복 설정이 있는 EventForm
9+ const baseEventForm : EventForm = {
10+ title : '매월 회의' ,
11+ date : '2024-01-15' ,
12+ startTime : '10:00' ,
13+ endTime : '11:00' ,
14+ description : '매월 정기 회의' ,
15+ location : '회의실 A' ,
16+ category : '업무' ,
17+ repeat : {
18+ type : 'monthly' ,
19+ interval : 1 ,
20+ endDate : '2024-04-15' ,
21+ } ,
22+ notificationTime : 10 ,
23+ } ;
24+
25+ // When: createRepeatEvents 함수 호출
26+ const events = createRepeatEvents ( baseEventForm ) ;
27+
28+ // Then: 반복 날짜별로 개별 Event 객체들이 생성됨 (각각 고유 ID 포함)
29+ expect ( events ) . toHaveLength ( 4 ) ; // 1월, 2월, 3월, 4월
30+ expect ( events [ 0 ] . date ) . toBe ( '2024-01-15' ) ;
31+ expect ( events [ 1 ] . date ) . toBe ( '2024-02-15' ) ;
32+ expect ( events [ 2 ] . date ) . toBe ( '2024-03-15' ) ;
33+ expect ( events [ 3 ] . date ) . toBe ( '2024-04-15' ) ;
34+
35+ // 모든 이벤트는 고유 ID를 가져야 함
36+ const ids = events . map ( event => event . id ) ;
37+ const uniqueIds = new Set ( ids ) ;
38+ expect ( uniqueIds . size ) . toBe ( events . length ) ;
39+
40+ // 모든 이벤트는 동일한 기본 정보를 가져야 함
41+ events . forEach ( event => {
42+ expect ( event . title ) . toBe ( baseEventForm . title ) ;
43+ expect ( event . startTime ) . toBe ( baseEventForm . startTime ) ;
44+ expect ( event . endTime ) . toBe ( baseEventForm . endTime ) ;
45+ expect ( event . description ) . toBe ( baseEventForm . description ) ;
46+ expect ( event . location ) . toBe ( baseEventForm . location ) ;
47+ expect ( event . category ) . toBe ( baseEventForm . category ) ;
48+ expect ( event . notificationTime ) . toBe ( baseEventForm . notificationTime ) ;
49+ } ) ;
50+ } ) ;
51+
52+ test ( '반복 없음 설정 이벤트는 단일 이벤트로만 생성된다' , ( ) => {
53+ // Given: repeat.type이 'none'인 EventForm
54+ const baseEventForm : EventForm = {
55+ title : '단일 일정' ,
56+ date : '2024-01-15' ,
57+ startTime : '14:00' ,
58+ endTime : '15:00' ,
59+ description : '한번만 실행되는 일정' ,
60+ location : '카페' ,
61+ category : '개인' ,
62+ repeat : {
63+ type : 'none' ,
64+ interval : 1 ,
65+ } ,
66+ notificationTime : 5 ,
67+ } ;
68+
69+ // When: createRepeatEvents 함수 호출
70+ const events = createRepeatEvents ( baseEventForm ) ;
71+
72+ // Then: 원본 이벤트 하나만 반환됨
73+ expect ( events ) . toHaveLength ( 1 ) ;
74+ expect ( events [ 0 ] . date ) . toBe ( '2024-01-15' ) ;
75+ expect ( events [ 0 ] . title ) . toBe ( baseEventForm . title ) ;
76+ expect ( events [ 0 ] . repeat . type ) . toBe ( 'none' ) ;
77+ } ) ;
78+ } ) ;
79+
80+ describe ( '반복 일정 개별 처리' , ( ) => {
81+ test ( '반복 일정 중 하나를 수정하면 단일 일정으로 변경된다' , ( ) => {
82+ // Given: 반복으로 생성된 여러 이벤트 중 특정 이벤트 ID
83+ const existingEvents : Event [ ] = [
84+ {
85+ id : 'repeat-1' ,
86+ title : '매주 운동' ,
87+ date : '2024-01-01' ,
88+ startTime : '07:00' ,
89+ endTime : '08:00' ,
90+ description : '주간 운동' ,
91+ location : '체육관' ,
92+ category : '건강' ,
93+ repeat : { type : 'weekly' , interval : 1 } ,
94+ notificationTime : 30 ,
95+ } ,
96+ {
97+ id : 'repeat-2' ,
98+ title : '매주 운동' ,
99+ date : '2024-01-08' ,
100+ startTime : '07:00' ,
101+ endTime : '08:00' ,
102+ description : '주간 운동' ,
103+ location : '체육관' ,
104+ category : '건강' ,
105+ repeat : { type : 'weekly' , interval : 1 } ,
106+ notificationTime : 30 ,
107+ } ,
108+ {
109+ id : 'repeat-3' ,
110+ title : '매주 운동' ,
111+ date : '2024-01-15' ,
112+ startTime : '07:00' ,
113+ endTime : '08:00' ,
114+ description : '주간 운동' ,
115+ location : '체육관' ,
116+ category : '건강' ,
117+ repeat : { type : 'weekly' , interval : 1 } ,
118+ notificationTime : 30 ,
119+ } ,
120+ ] ;
121+
122+ const updates = {
123+ title : '특별 운동 세션' ,
124+ startTime : '08:00' ,
125+ endTime : '09:30' ,
126+ description : '개별 수정된 운동' ,
127+ } ;
128+
129+ // When: updateSingleRepeatEvent 함수로 해당 이벤트 수정
130+ const updatedEvents = updateSingleRepeatEvent ( existingEvents , 'repeat-2' , updates ) ;
131+
132+ // Then: 해당 이벤트의 repeat.type이 'none'으로 변경되고 내용이 업데이트됨
133+ const updatedEvent = updatedEvents . find ( event => event . id === 'repeat-2' ) ;
134+ expect ( updatedEvent ) . toBeDefined ( ) ;
135+ expect ( updatedEvent ! . repeat . type ) . toBe ( 'none' ) ;
136+ expect ( updatedEvent ! . title ) . toBe ( '특별 운동 세션' ) ;
137+ expect ( updatedEvent ! . startTime ) . toBe ( '08:00' ) ;
138+ expect ( updatedEvent ! . endTime ) . toBe ( '09:30' ) ;
139+ expect ( updatedEvent ! . description ) . toBe ( '개별 수정된 운동' ) ;
140+
141+ // 다른 이벤트들은 변경되지 않아야 함
142+ const otherEvents = updatedEvents . filter ( event => event . id !== 'repeat-2' ) ;
143+ otherEvents . forEach ( event => {
144+ expect ( event . repeat . type ) . toBe ( 'weekly' ) ;
145+ expect ( event . title ) . toBe ( '매주 운동' ) ;
146+ } ) ;
147+ } ) ;
148+
149+ test ( '반복 일정 중 하나를 삭제하면 해당 이벤트만 삭제된다' , ( ) => {
150+ // Given: 반복으로 생성된 여러 이벤트가 저장된 상태
151+ const existingEvents : Event [ ] = [
152+ {
153+ id : 'daily-1' ,
154+ title : '매일 독서' ,
155+ date : '2024-01-01' ,
156+ startTime : '20:00' ,
157+ endTime : '21:00' ,
158+ description : '일일 독서 시간' ,
159+ location : '집' ,
160+ category : '자기계발' ,
161+ repeat : { type : 'daily' , interval : 1 } ,
162+ notificationTime : 15 ,
163+ } ,
164+ {
165+ id : 'daily-2' ,
166+ title : '매일 독서' ,
167+ date : '2024-01-02' ,
168+ startTime : '20:00' ,
169+ endTime : '21:00' ,
170+ description : '일일 독서 시간' ,
171+ location : '집' ,
172+ category : '자기계발' ,
173+ repeat : { type : 'daily' , interval : 1 } ,
174+ notificationTime : 15 ,
175+ } ,
176+ {
177+ id : 'daily-3' ,
178+ title : '매일 독서' ,
179+ date : '2024-01-03' ,
180+ startTime : '20:00' ,
181+ endTime : '21:00' ,
182+ description : '일일 독서 시간' ,
183+ location : '집' ,
184+ category : '자기계발' ,
185+ repeat : { type : 'daily' , interval : 1 } ,
186+ notificationTime : 15 ,
187+ } ,
188+ ] ;
189+
190+ // When: deleteSingleRepeatEvent 함수로 특정 이벤트 삭제
191+ const remainingEvents = deleteSingleRepeatEvent ( existingEvents , 'daily-2' ) ;
192+
193+ // Then: 해당 이벤트만 삭제되고 나머지 반복 이벤트들은 유지됨
194+ expect ( remainingEvents ) . toHaveLength ( 2 ) ;
195+ expect ( remainingEvents . find ( event => event . id === 'daily-2' ) ) . toBeUndefined ( ) ;
196+ expect ( remainingEvents . find ( event => event . id === 'daily-1' ) ) . toBeDefined ( ) ;
197+ expect ( remainingEvents . find ( event => event . id === 'daily-3' ) ) . toBeDefined ( ) ;
198+
199+ // 남은 이벤트들은 여전히 반복 설정을 유지해야 함
200+ remainingEvents . forEach ( event => {
201+ expect ( event . repeat . type ) . toBe ( 'daily' ) ;
202+ } ) ;
203+ } ) ;
204+ } ) ;
205+
206+ describe ( '반복 일정 시각적 구분 처리' , ( ) => {
207+ test ( '반복 이벤트는 시각적 구분을 위한 플래그를 가진다' , ( ) => {
208+ // Given: 반복 설정으로 생성된 이벤트들
209+ const events : Event [ ] = [
210+ {
211+ id : 'repeat-1' ,
212+ title : '반복 일정' ,
213+ date : '2024-01-01' ,
214+ startTime : '10:00' ,
215+ endTime : '11:00' ,
216+ description : '' ,
217+ location : '' ,
218+ category : '' ,
219+ repeat : { type : 'weekly' , interval : 1 } ,
220+ notificationTime : 0 ,
221+ } ,
222+ {
223+ id : 'single-1' ,
224+ title : '단일 일정' ,
225+ date : '2024-01-02' ,
226+ startTime : '14:00' ,
227+ endTime : '15:00' ,
228+ description : '' ,
229+ location : '' ,
230+ category : '' ,
231+ repeat : { type : 'none' , interval : 1 } ,
232+ notificationTime : 0 ,
233+ } ,
234+ ] ;
235+
236+ // When: 이벤트 목록을 확인할 때
237+ const markedEvents = markRepeatEvents ( events ) ;
238+
239+ // Then: 각 반복 이벤트는 isRepeatEvent 플래그가 true로 설정됨
240+ const repeatEvent = markedEvents . find ( event => event . id === 'repeat-1' ) ;
241+ const singleEvent = markedEvents . find ( event => event . id === 'single-1' ) ;
242+
243+ expect ( repeatEvent ) . toHaveProperty ( 'isRepeatEvent' , true ) ;
244+ expect ( singleEvent ) . toHaveProperty ( 'isRepeatEvent' , false ) ;
245+ } ) ;
246+
247+ test ( '단일 수정된 반복 이벤트는 반복 표시가 제거된다' , ( ) => {
248+ // Given: 반복으로 생성된 이벤트 중 하나가 수정된 상태
249+ const events : Event [ ] = [
250+ {
251+ id : 'modified-repeat' ,
252+ title : '수정된 일정' ,
253+ date : '2024-01-01' ,
254+ startTime : '10:00' ,
255+ endTime : '11:00' ,
256+ description : '단일 수정됨' ,
257+ location : '' ,
258+ category : '' ,
259+ repeat : { type : 'none' , interval : 1 } , // 단일 수정으로 인해 'none'으로 변경됨
260+ notificationTime : 0 ,
261+ } ,
262+ ] ;
263+
264+ // When: 해당 이벤트의 상태를 확인할 때
265+ const markedEvents = markRepeatEvents ( events ) ;
266+
267+ // Then: isRepeatEvent 플래그가 false로 변경됨
268+ const modifiedEvent = markedEvents . find ( event => event . id === 'modified-repeat' ) ;
269+ expect ( modifiedEvent ) . toHaveProperty ( 'isRepeatEvent' , false ) ;
270+ } ) ;
271+ } ) ;
0 commit comments