Skip to content
Snippets Groups Projects
meetingService.test.js 18.5 KiB
Newer Older
// test/meetingService.test.js
const sequelize = require('../config/sequelize'); 
const { Op } = require('sequelize');
const { Meeting, MeetingParticipant, User, Schedule } = require('../models');
const MeetingService = require('../services/meetingService');
const ScheduleService = require('../services/scheduleService');
const ChatRooms = require('../models/ChatRooms'); 
const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO');
const MeetingResponseDTO = require('../dtos/MeetingResponseDTO');
const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO');
beforeAll(async () => {
  // 데이터베이스 초기화 및 동기화
  await sequelize.sync({ force: true });
beforeEach(async () => {
  // 외래 키 순서에 따라 데이터 삭제
  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();
afterAll(async () => {
  // 데이터베이스 연결 종료
  await sequelize.close();
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('스케줄이 겹칩니다. 다른 모임에 참가하세요.');

});

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)
  });
});