Skip to content
Snippets Groups Projects
Commit e0c7ec1c authored by tpgus2603's avatar tpgus2603
Browse files

test/refactor : 서비스코드 리펙토링(#13)

parent c3666785
No related branches found
No related tags found
2 merge requests!31Develop,!23[#13] 스케쥴 서비스 코드 로직 대폭 수정 및 미팅서비스 테스트 완료
// dtos/MeetingResponseDTO.js
class MeetingResponseDTO {
constructor(meeting, isParticipant, isScheduleConflict, creatorName) {
class MeetingDetailResponseDTO {
constructor(meeting) {
this.id = meeting.id;
this.title = meeting.title;
this.description = meeting.description;
this.timeIdxStart = meeting.time_idx_start; // 변경된 필드
this.timeIdxEnd = meeting.time_idx_end; // 변경된 필드
this.timeIdxStart = meeting.time_idx_start;
this.timeIdxEnd = meeting.time_idx_end;
this.location = meeting.location;
this.deadline = meeting.deadline;
this.time_idx_deadline = meeting.time_idx_deadline;
this.type = meeting.type;
this.creatorName = creatorName;
this.isParticipant = isParticipant;
this.isScheduleConflict = isScheduleConflict;
this.creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
this.participants = meeting.participants.map(participant => ({
userId: participant.user_id,
name: participant.participantUser ? participant.participantUser.name : 'Unknown',
email: participant.participantUser ? participant.participantUser.email : 'Unknown'
}));
}
}
module.exports = MeetingResponseDTO;
module.exports = MeetingDetailResponseDTO;
\ No newline at end of file
// dtos/MeetingDetailResponseDTO.js
class MeetingDetailResponseDTO {
constructor(meeting) {
class MeetingResponseDTO {
constructor(meeting, isParticipant, isScheduleConflict, creatorName) {
this.id = meeting.id;
this.title = meeting.title;
this.description = meeting.description;
this.timeIdxStart = meeting.time_idx_start;
this.timeIdxEnd = meeting.time_idx_end;
this.location = meeting.location;
this.deadline = meeting.deadline;
this.time_idx_deadline = meeting.time_idx_deadline;
this.type = meeting.type;
this.creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
this.participants = meeting.participants.map(participant => ({
userId: participant.user_id,
name: participant.participantUser ? participant.participantUser.name : 'Unknown',
email: participant.participantUser ? participant.participantUser.email : 'Unknown'
}));
this.creatorName = creatorName;
this.isParticipant = isParticipant;
this.isScheduleConflict = isScheduleConflict;
}
}
module.exports = MeetingDetailResponseDTO;
module.exports = MeetingResponseDTO;
\ No newline at end of file
// middlewares/auth.js
exports.isLoggedIn = (req, res, next) => {
exports.isLoggedIn = (req, res, next) => { //로그인된 사용자자만 접근허용
if (req.isAuthenticated()) {
return next();
}
res.redirect('/auth/login');
};
exports.isNotLoggedIn = (req, res, next) => {
exports.isNotLoggedIn = (req, res, next) => { //로그인 안되면 리다이렉트
if (!req.isAuthenticated()) {
return next();
}
......
......@@ -2,7 +2,7 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const User = require('./user');
const Friend = sequelize.define('Friend', {
status: {
......@@ -25,11 +25,4 @@ const Friend = sequelize.define('Friend', {
]
});
// // 관계 설정
// Friend.belongsTo(User, { foreignKey: 'requester_id', as: 'requester' }); // 친구 요청을 보낸 사용자
// Friend.belongsTo(User, { foreignKey: 'receiver_id', as: 'receiver' }); // 친구 요청을 받은 사용자
// User.hasMany(Friend, { foreignKey: 'requester_id', as: 'sentRequests' }); // 친구 요청을 보낸 목록
// User.hasMany(Friend, { foreignKey: 'receiver_id', as: 'receivedRequests' }); // 친구 요청을 받은 목록
module.exports = Friend;
// models/index.js
const sequelize = require('../config/sequelize');
const User = require('./User');
const User = require('./user');
const Friend = require('./Friend');
const Schedule = require('./Schedule');
const Meeting = require('./Meeting');
const MeetingParticipant = require('./MeetingParticipant');
const ChatRoom = require('./ChatRooms');
const ChatRooms = require('./ChatRooms');
// 관계 설정
Friend.belongsTo(User, { foreignKey: 'requester_id', as: 'requester' }); // 친구 요청을 보낸 사용자
......@@ -34,5 +34,5 @@ module.exports = {
Schedule,
Meeting,
MeetingParticipant,
ChatRoom,
ChatRooms,
};
// models/Meeting.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const User = require('./user');
const Meeting = sequelize.define('Meeting', {
title: {
......@@ -22,7 +22,7 @@ const Meeting = sequelize.define('Meeting', {
location: {
type: DataTypes.STRING,
},
deadline: {
time_idx_deadline: {
type: DataTypes.INTEGER,
},
type: {
......@@ -34,11 +34,4 @@ const Meeting = sequelize.define('Meeting', {
timestamps: false,
});
// // 연관 관계 설정
// Meeting.belongsTo(User, { foreignKey: 'created_by', as: 'creator' });
// User.hasMany(Meeting, { foreignKey: 'created_by', as: 'meetings' });
// Meeting.belongsTo(ChatRoom, { foreignKey: 'chatRoomId', as: 'chatRoom' });
// ChatRoom.hasOne(Meeting, { foreignKey: 'chatRoomId', as: 'meeting' });
module.exports = Meeting;
......@@ -3,28 +3,13 @@
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const Meeting =require('./Meeting');
const User = require('./User');
const User = require('./user');
const MeetingParticipant = sequelize.define('MeetingParticipant', {
meeting_id: {
type: DataTypes.INTEGER,
allowNull: false
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false
}
}, {
tableName: 'MeetingParticipants',
timestamps: false,
});
// MeetingParticipant.belongsTo(Meeting, { foreignKey: 'meeting_id', as: 'meeting' });
// Meeting.hasMany(MeetingParticipant, { foreignKey: 'meeting_id', as: 'participants' });
// MeetingParticipant.belongsTo(User, { foreignKey: 'user_id', as: 'user' });
// User.hasMany(MeetingParticipant, { foreignKey: 'user_id', as: 'meetingParticipations' });
module.exports = MeetingParticipant;
// models/Schedule.js
const { DataTypes } = require('sequelize');
const sequelize = require('../config/sequelize');
const User = require('./User');
const User = require('./user');
const Schedule = sequelize.define('Schedule', {
title: {
......
......@@ -122,40 +122,37 @@ class MeetingService {
* @returns {Promise<Array<MeetingResponseDTO>>} - 모임 목록 DTO 배열
*/
async getMeetings(userId) {
const meetings = await Meeting.findAll({
attributes: [
'id',
'title',
'description',
'time_idx_start',
'time_idx_end',
'location',
'time_idx_deadline',
'type',
],
include: [
{
model: User,
as: 'creator',
attributes: ['name'],
},
{
model: MeetingParticipant,
as: 'participants',
attributes: ['user_id'],
},
],
});
return meetings.map((meeting) => {
const creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
const isParticipant = meeting.participants.some(
(participant) => participant.user_id === parseInt(userId, 10)
);
return new MeetingResponseDTO(meeting, isParticipant, false, creatorName);
});
}
const meetings = await Meeting.findAll({
attributes: [
'id',
'title',
'description',
'time_idx_start',
'time_idx_end',
'location',
'time_idx_deadline',
'type',
],
include: [
{
model: MeetingParticipant,
as: 'participants',
where: { user_id: userId }, // userId와 매핑된 미팅만 가져옴
attributes: [], // MeetingParticipant 테이블의 데이터는 필요 없으므로 제외
},
{
model: User,
as: 'creator',
attributes: ['name'], // 미팅 생성자의 이름만 필요
},
],
});
return meetings.map((meeting) => {
const creatorName = meeting.creator ? meeting.creator.name : 'Unknown';
return new MeetingResponseDTO(meeting, true, false, creatorName);
});
}
/**
* 번개 모임 마감
......@@ -262,34 +259,35 @@ class MeetingService {
* @param {number} meetingId - 모임 ID
* @returns {Promise<MeetingDetailResponseDTO>} - 모임 상세 DTO
*/
async getMeetingDetail(meetingId) {
const meeting = await Meeting.findByPk(meetingId, {
include: [
{
model: User,
as: 'creator',
attributes: ['name'],
},
{
model: MeetingParticipant,
as: 'participants',
include: [
{
model: User,
as: 'participantUser',
attributes: ['name', 'email'],
},
],
},
],
});
if (!meeting) {
throw new Error('모임을 찾을 수 없습니다.');
}
return new MeetingDetailResponseDTO(meeting);
// services/meetingService.js
async getMeetingDetail(meetingId) {
const meeting = await Meeting.findByPk(meetingId, {
include: [
{
model: User,
as: "creator",
attributes: ["name"],
},
{
model: MeetingParticipant,
as: "participants",
include: [
{
model: User,
as: "user", // 'participantUser'에서 'user'로 수정
attributes: ["name", "email"],
},
],
},
],
});
if (!meeting) {
throw new Error("모임을 찾을 수 없습니다.");
}
return new MeetingDetailResponseDTO(meeting);
}
}
module.exports = new MeetingService();
......@@ -9,6 +9,14 @@ const CreateMeetingRequestDTO = require('../dtos/CreateMeetingRequestDTO');
const MeetingResponseDTO = require('../dtos/MeetingResponseDTO');
const MeetingDetailResponseDTO = require('../dtos/MeetingDetailResponseDTO');
// Jest 설정에서 'node' 환경을 사용하고 있는지 확인
// jest.config.js 또는 package.json에 다음을 추가하세요:
// {
// "jest": {
// "testEnvironment": "node"
// }
// }
// ChatRooms 모듈 전체를 모킹하지 않고, 필요한 메서드만 선택적으로 모킹합니다.
beforeAll(async () => {
// 테스트 스위트가 시작되기 전에 데이터베이스를 동기화합니다.
......@@ -129,6 +137,11 @@ describe('MeetingService', () => {
created_by: 1,
};
// 'createSchedules' 메서드에서 'Schedule overlaps with existing schedule at time_idx 50' 오류가 발생해야 함
// 이를 위해 'ScheduleService.checkScheduleOverlapByTime'을 모킹합니다.
jest.spyOn(ScheduleService, 'checkScheduleOverlapByTime').mockResolvedValue(true); // 충돌이 발생한다고 가정
await expect(MeetingService.createMeeting(meetingData)).rejects.toThrow(
'Schedule overlaps with existing schedule at time_idx 50'
);
......@@ -160,28 +173,31 @@ describe('MeetingService', () => {
created_by: 2,
};
await MeetingService.createMeeting(meetingData1);
await MeetingService.createMeeting(meetingData2);
const result1 = await MeetingService.createMeeting(meetingData1);
const result2 = await MeetingService.createMeeting(meetingData2);
const meetings = await MeetingService.getMeetings(1); // Alice의 사용자 ID
console.log(meetings);
expect(meetings).toBeDefined();
expect(Array.isArray(meetings)).toBe(true);
expect(meetings.length).toBe(2);
meetings.forEach(meeting => {
expect(meeting).toBeInstanceOf(MeetingResponseDTO);
expect(['Meeting 1', 'Meeting 2']).toContain(meeting.title);
expect(['OPEN']).toContain(meeting.type);
if (meeting.id === 1) {
expect(meeting.creatorName).toBe('Alice');
expect(meeting.isParticipant).toBe(true);
} else {
expect(meeting.creatorName).toBe('Bob');
expect(meeting.isParticipant).toBe(false);
}
});
expect(meetings.length).toBe(1);
// 생성된 미팅의 ID를 기준으로 기대값 설정
const meeting1 = meetings.find(meeting => meeting.title === 'Meeting 1');
const meeting2 = meetings.find(meeting => meeting.title === 'Meeting 2');
console.log(meeting1);
console.log(meeting2);
expect(meeting1).toBeDefined();
expect(meeting1.creatorName).toBe('Alice');
expect(meeting1.isParticipant).toBe(true);
expect(meeting2).toBeDefined();
expect(meeting2.creatorName).toBe('Bob');
expect(meeting2.isParticipant).toBe(false);
});
// 추가적인 getMeetings 테스트 케이스 작성 가능
});
describe('closeMeeting', () => {
......@@ -248,6 +264,9 @@ describe('MeetingService', () => {
const { meeting_id } = await MeetingService.createMeeting(meetingData);
// 'getCurrentTimeIdx'를 고정된 값으로 모킹하여 '참가 신청이 마감되었습니다.' 오류를 방지
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(100); // 100 < 108
// Bob이 참가
await MeetingService.joinMeeting(meeting_id, 2);
......@@ -290,6 +309,9 @@ describe('MeetingService', () => {
const { meeting_id } = await MeetingService.createMeeting(meetingData);
// 'getCurrentTimeIdx'를 고정된 값으로 모킹
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(100); // 100 < 118
await MeetingService.closeMeeting(meeting_id);
await expect(MeetingService.joinMeeting(meeting_id, 2)).rejects.toThrow('이미 마감된 모임입니다.');
......@@ -309,6 +331,9 @@ describe('MeetingService', () => {
const { meeting_id } = await MeetingService.createMeeting(meetingData);
// 'getCurrentTimeIdx'를 고정된 값으로 모킹
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(100); // 100 < 128
await MeetingService.joinMeeting(meeting_id, 2);
await expect(MeetingService.joinMeeting(meeting_id, 2)).rejects.toThrow('이미 참가한 사용자입니다.');
......@@ -322,13 +347,19 @@ describe('MeetingService', () => {
time_idx_start: 59,
time_idx_end: 61, // time_idx 60 포함
location: 'Conference Room H',
time_idx_deadline: 58,
time_idx_deadline: 110, // 참가 신청 마감을 피하기 위해 값 변경
type: 'OPEN',
created_by: 1,
};
const { meeting_id } = await MeetingService.createMeeting(meetingData);
// 'getCurrentTimeIdx'를 고정된 값으로 모킹
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(100); // 100 < 110
// 'checkScheduleOverlapByTime'을 모킹하여 충돌이 발생하도록 설정
jest.spyOn(ScheduleService, 'checkScheduleOverlapByTime').mockResolvedValue(true);
await expect(MeetingService.joinMeeting(meeting_id, 2)).rejects.toThrow(
'스케줄이 겹칩니다. 다른 모임에 참가하세요.'
);
......@@ -351,6 +382,7 @@ describe('MeetingService', () => {
const { meeting_id } = await MeetingService.createMeeting(meetingData);
// Bob과 Charlie 참가
jest.spyOn(MeetingService, 'getCurrentTimeIdx').mockReturnValue(100); // 참가 신청 마감 방지
await MeetingService.joinMeeting(meeting_id, 2);
await MeetingService.joinMeeting(meeting_id, 3);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment