Newer
Older
const { Op } = require('sequelize');
const { Meeting, MeetingParticipant, User, Schedule } = require('../models');
const MeetingService = require('../services/meetingService');
const ScheduleService = require('../services/scheduleService');
const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO');
const MeetingResponseDTO = require('../dtos/MeetingResponseDTO');
const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO');
// 데이터베이스 초기화 및 동기화
await sequelize.sync({ force: true });
// 외래 키 순서에 따라 데이터 삭제
await MeetingParticipant.destroy({ where: {}, truncate: true });
await Meeting.destroy({ where: {}, truncate: true });
await Schedule.destroy({ where: {}, truncate: true });
await User.destroy({ where: {}, truncate: true });
// 더미 사용자 데이터 삽입
await User.bulkCreate([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com' },
]);
// ChatRooms Mock 설정
jest.spyOn(ChatRooms.prototype, 'save').mockResolvedValue(undefined);
jest.spyOn(ChatRooms, 'findOne').mockResolvedValue({
participants: [],
isOnline: new Map(),
lastReadAt: new Map(),
lastReadLogId: new Map(),
save: jest.fn().mockResolvedValue(true),
});
});
afterEach(() => {
// Mock 복원 및 초기화
jest.restoreAllMocks();
jest.clearAllMocks();
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
describe('MeetingService - getMeetings', () => {
beforeEach(async () => {
await MeetingParticipant.destroy({ where: {} });
await Meeting.destroy({ where: {} });
await Schedule.destroy({ where: {} });
await User.destroy({ where: {} });
// Create dummy users
await User.bulkCreate([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com' },
]);
});
test('should retrieve meetings where the user is a participant', async () => {
const meetingData = {
title: 'Meeting with Alice',
description: 'Discuss project.',
time_idx_start: 10,
time_idx_end: 20,
location: 'Room A',
time_idx_deadline: 8,
type: 'OPEN',
created_by: 1,
};
const createdMeeting = await MeetingService.createMeeting(meetingData);
await MeetingParticipant.create({
meeting_id: createdMeeting.meeting_id,
user_id: 2,
});
const meetings = await MeetingService.getMeetings(2); // Bob's user ID
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(1);
const [meeting] = meetings;
expect(meeting.title).toBe('Meeting with Alice');
expect(meeting.creatorName).toBe('Alice');
expect(meeting.isParticipant).toBe(true);
});
test('should retrieve meetings where the user is the creator', async () => {
const meetingData = {
title: 'Alice-created Meeting',
description: 'Team discussion.',
time_idx_start: 15,
time_idx_end: 25,
location: 'Room B',
time_idx_deadline: 12,
type: 'OPEN',
created_by: 1,
};
await MeetingService.createMeeting(meetingData);
const meetings = await MeetingService.getMeetings(1); // Alice's user ID
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(1);
const [meeting] = meetings;
expect(meeting.title).toBe('Alice-created Meeting');
expect(meeting.creatorName).toBe('Alice');
expect(meeting.isParticipant).toBe(true);
});
test('should not include meetings where the user is neither a participant nor the creator', async () => {
const meetingData = {
title: 'Meeting with Bob',
description: 'General discussion.',
time_idx_start: 30,
time_idx_end: 40,
location: 'Room C',
time_idx_deadline: 28,
type: 'OPEN',
created_by: 2,
};
await MeetingService.createMeeting(meetingData);
const meetings = await MeetingService.getMeetings(1); // Alice's user ID
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(0); // Alice is not a participant or the creator
});
test('should retrieve multiple meetings correctly', async () => {
const meetingData1 = {
title: 'Meeting 1',
description: 'First meeting.',
time_idx_start: 50,
time_idx_end: 60,
location: 'Room D',
time_idx_deadline: 48,
type: 'OPEN',
created_by: 1,
};
const meetingData2 = {
title: 'Meeting 2',
description: 'Second meeting.',
time_idx_start: 70,
time_idx_end: 80,
location: 'Room E',
time_idx_deadline: 68,
type: 'OPEN',
created_by: 2,
};
await MeetingService.createMeeting(meetingData1);
const meeting2 = await MeetingService.createMeeting(meetingData2);
await MeetingParticipant.create({
meeting_id: meeting2.meeting_id,
user_id: 1,
});
const meetings = await MeetingService.getMeetings(1); // Alice's user ID
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(2); // Alice is either the creator or a participant in two meetings
const meetingTitles = meetings.map((m) => m.title);
expect(meetingTitles).toContain('Meeting 1');
expect(meetingTitles).toContain('Meeting 2');
});
test('should return an empty array if the user has no meetings', async () => {
const meetings = await MeetingService.getMeetings(3);
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(0);
});
});
describe('MeetingService - Integration: createMeeting, joinMeeting, getMeetings', () => {
beforeEach(async () => {
await MeetingParticipant.destroy({ where: {} });
await Meeting.destroy({ where: {} });
await Schedule.destroy({ where: {} });
await User.destroy({ where: {} });
// Create dummy users
await User.bulkCreate([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com' },
]);
});
test('should create a meeting, allow multiple users to join, and retrieve them correctly', async () => {
// Step 1: Create a meeting
const meetingData = {
title: 'Integration Test Meeting',
description: 'Test meeting for integration.',
time_idx_start: 10,
time_idx_end: 20,
location: 'Conference Room A',
time_idx_deadline: 8,
type: 'OPEN',
created_by: 1,
};
const createdMeeting = await MeetingService.createMeeting(meetingData);
expect(createdMeeting).toBeDefined();
expect(createdMeeting.meeting_id).toBeDefined();
expect(createdMeeting.chatRoomId).toBeDefined();
// Step 2: Bob and Charlie join the meeting
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(5); // Ensure deadline is not passed
await MeetingService.joinMeeting(createdMeeting.meeting_id, 2); // Bob joins
await MeetingService.joinMeeting(createdMeeting.meeting_id, 3); // Charlie joins
// Step 3: Retrieve meetings for Alice (creator)
const aliceMeetings = await MeetingService.getMeetings(1);
expect(aliceMeetings).toBeDefined();
expect(aliceMeetings.length).toBe(1);
const aliceMeeting = aliceMeetings[0];
expect(aliceMeeting.title).toBe('Integration Test Meeting');
expect(aliceMeeting.creatorName).toBe('Alice');
expect(aliceMeeting.isParticipant).toBe(true);
// Step 4: Retrieve meetings for Bob (participant)
const bobMeetings = await MeetingService.getMeetings(2);
expect(bobMeetings).toBeDefined();
expect(bobMeetings.length).toBe(1);
const bobMeeting = bobMeetings[0];
expect(bobMeeting.title).toBe('Integration Test Meeting');
expect(bobMeeting.creatorName).toBe('Alice');
expect(bobMeeting.isParticipant).toBe(true);
// Step 5: Retrieve meetings for Charlie (participant)
const charlieMeetings = await MeetingService.getMeetings(3);
expect(charlieMeetings).toBeDefined();
expect(charlieMeetings.length).toBe(1);
const charlieMeeting = charlieMeetings[0];
expect(charlieMeeting.title).toBe('Integration Test Meeting');
expect(charlieMeeting.creatorName).toBe('Alice');
expect(charlieMeeting.isParticipant).toBe(true);
});
test('should not allow joining a meeting after the deadline', async () => {
const meetingData = {
title: 'Deadline Test Meeting',
description: 'Meeting to test deadlines.',
time_idx_start: 30,
time_idx_end: 40,
location: 'Conference Room B',
time_idx_deadline: 25,
type: 'OPEN',
created_by: 1, // Alice creates the meeting
};
const createdMeeting = await MeetingService.createMeeting(meetingData);
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(26); // Simulate time after the deadline
await expect(
MeetingService.joinMeeting(createdMeeting.meeting_id, 2)
).rejects.toThrow('참가 신청이 마감되었습니다.');
});
test('should prevent duplicate joining of a meeting', async () => {
const meetingData = {
title: 'Duplicate Join Test Meeting',
description: 'Meeting to test duplicate join handling.',
time_idx_start: 50,
time_idx_end: 60,
location: 'Conference Room C',
time_idx_deadline: 48,
type: 'OPEN',
created_by: 1, // Alice creates the meeting
};
const createdMeeting = await MeetingService.createMeeting(meetingData);
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(45); // Ensure deadline is not passed
await MeetingService.joinMeeting(createdMeeting.meeting_id, 2); // Bob joins
// Attempt duplicate join
await expect(
MeetingService.joinMeeting(createdMeeting.meeting_id, 2)
).rejects.toThrow('이미 참가한 사용자입니다.');
});
test('should prevent joining when schedule conflicts', async () => {
const meetingData = {
title: 'Conflict Test Meeting',
description: 'Meeting to test schedule conflict.',
time_idx_start: 70,
time_idx_end: 80,
location: 'Conference Room D',
time_idx_deadline: 68,
type: 'OPEN',
created_by: 1, // Alice creates the meeting
};
const createdMeeting = await MeetingService.createMeeting(meetingData);
// Step 1: Virtually set current time before the deadline
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(65); // 현재 시간이 데드라인보다 작음
// Step 2: Simulate schedule conflict
jest.spyOn(ScheduleService, 'checkScheduleOverlapByTime').mockResolvedValue(true); // 스케줄 충돌 발생
// Step 3: Expect schedule conflict error
await expect(
MeetingService.joinMeeting(createdMeeting.meeting_id, 2)
).rejects.toThrow('스케줄이 겹칩니다. 다른 모임에 참가하세요.');
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
});
describe('MeetingService2', () => {
beforeEach(async () => {
// 데이터베이스 초기화
await MeetingParticipant.destroy({ where: {} });
await Meeting.destroy({ where: {} });
await Schedule.destroy({ where: {} });
await User.destroy({ where: {} });
// 더미 사용자 생성
await User.bulkCreate([
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com' },
]);
});
test('사용자가 여러 모임에 참여하고 이를 정확히 조회할 수 있어야 한다', async () => {
// 1단계: 겹치지 않는 시간대의 모임 생성
const meetingData1 = {
title: 'Morning Meeting',
description: 'Morning planning meeting.',
time_idx_start: 10,
time_idx_end: 20,
location: 'Room A',
time_idx_deadline: 8,
type: 'OPEN',
created_by: 1, // Alice가 모임 생성
};
const meetingData2 = {
title: 'Lunch Meeting',
description: 'Lunch and discussion.',
time_idx_start: 30,
time_idx_end: 40,
location: 'Room B',
time_idx_deadline: 28,
type: 'OPEN',
created_by: 2, // Bob이 모임 생성
};
const meeting1 = await MeetingService.createMeeting(meetingData1);
const meeting2 = await MeetingService.createMeeting(meetingData2);
// 모임 생성 확인
expect(meeting1).toBeDefined();
expect(meeting2).toBeDefined();
// 2단계: Charlie가 두 모임에 참여
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(5); // 마감 시간을 초과하지 않도록 설정
await MeetingService.joinMeeting(meeting1.meeting_id, 3); // Charlie가 Morning Meeting 참여
await MeetingService.joinMeeting(meeting2.meeting_id, 3); // Charlie가 Lunch Meeting 참여
// 3단계: Charlie의 참여 모임 조회
const charlieMeetings = await MeetingService.getMeetings(3); // Charlie의 사용자 ID
expect(charlieMeetings).toBeDefined();
expect(Array.isArray(charlieMeetings)).toBe(true);
expect(charlieMeetings.length).toBe(2); // Charlie는 2개의 모임에 참여
// 각 모임의 세부 정보 확인
const morningMeeting = charlieMeetings.find(meeting => meeting.title === 'Morning Meeting');
const lunchMeeting = charlieMeetings.find(meeting => meeting.title === 'Lunch Meeting');
expect(morningMeeting).toBeDefined();
expect(morningMeeting.creatorName).toBe('Alice');
expect(morningMeeting.isParticipant).toBe(true);
expect(lunchMeeting).toBeDefined();
expect(lunchMeeting.creatorName).toBe('Bob');
expect(lunchMeeting.isParticipant).toBe(true);
// 추가 검증: 각 모임에 대한 Charlie의 스케줄이 올바르게 생성되었는지 확인
const charlieSchedules = await Schedule.findAll({ where: { user_id: 3 } });
expect(charlieSchedules.length).toBe(2 * (20 - 10 + 1)); // 두 모임, 각 모임마다 11개의 스케줄 (10~20, 30~40)
// 중복 스케줄이 없는지 확인
const timeIndicesMorning = charlieSchedules
.filter(schedule => schedule.title === `번개 모임: ${meetingData1.title}`)
.map(schedule => schedule.time_idx);
const timeIndicesLunch = charlieSchedules
.filter(schedule => schedule.title === `번개 모임: ${meetingData2.title}`)
.map(schedule => schedule.time_idx);
// Morning Meeting의 시간대 확인
for (let i = 10; i <= 20; i++) {
expect(timeIndicesMorning).toContain(i);
}
// Lunch Meeting의 시간대 확인
for (let i = 30; i <= 40; i++) {
expect(timeIndicesLunch).toContain(i);
}
});
test('각 사용자의 모임을 정확히 조회해야 한다', async () => {
// 1단계: 겹치지 않는 시간대의 모임 생성
const meetingData1 = {
title: 'Morning Meeting',
description: 'Morning planning meeting.',
time_idx_start: 10,
time_idx_end: 20,
location: 'Room A',
time_idx_deadline: 8,
type: 'OPEN',
created_by: 1, // Alice가 모임 생성
};
const meetingData2 = {
title: 'Lunch Meeting',
description: 'Lunch and discussion.',
time_idx_start: 30,
time_idx_end: 40,
location: 'Room B',
time_idx_deadline: 28,
type: 'OPEN',
created_by: 2, // Bob이 모임 생성
};
const meeting1 = await MeetingService.createMeeting(meetingData1);
const meeting2 = await MeetingService.createMeeting(meetingData2);
// 2단계: Charlie가 두 모임에 참여
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(5); // 마감 시간을 초과하지 않도록 설정
await MeetingService.joinMeeting(meeting1.meeting_id, 3); // Charlie가 Morning Meeting 참여
await MeetingService.joinMeeting(meeting2.meeting_id, 3); // Charlie가 Lunch Meeting 참여
// 3단계: Alice의 모임 조회
const aliceMeetings = await MeetingService.getMeetings(1); // Alice의 사용자 ID
expect(aliceMeetings.length).toBe(1); // Alice는 하나의 모임 생성
expect(aliceMeetings[0].title).toBe('Morning Meeting');
expect(aliceMeetings[0].isParticipant).toBe(true);
// 4단계: Bob의 모임 조회
const bobMeetings = await MeetingService.getMeetings(2); // Bob의 사용자 ID
expect(bobMeetings.length).toBe(1); // Bob은 하나의 모임 생성
expect(bobMeetings[0].title).toBe('Lunch Meeting');
expect(bobMeetings[0].isParticipant).toBe(true);
// 5단계: Charlie의 모임 조회
const charlieMeetings = await MeetingService.getMeetings(3); // Charlie의 사용자 ID
expect(charlieMeetings.length).toBe(2); // Charlie는 두 모임에 참여
const meetingTitles = charlieMeetings.map(meeting => meeting.title);
expect(meetingTitles).toContain('Morning Meeting');
expect(meetingTitles).toContain('Lunch Meeting');
// 추가 검증: 각 사용자의 스케줄을 확인하여 충돌이 없는지 확인
const aliceSchedules = await Schedule.findAll({ where: { user_id: 1 } });
expect(aliceSchedules.length).toBe(11); // Morning Meeting: 10-20
const bobSchedules = await Schedule.findAll({ where: { user_id: 2 } });
expect(bobSchedules.length).toBe(11); // Lunch Meeting: 30-40
const charlieSchedules = await Schedule.findAll({ where: { user_id: 3 } });
expect(charlieSchedules.length).toBe(22); // 두 모임, 각 모임마다 11개의 스케줄 (10~20, 30~40)
});
});