Skip to content

Commit 9081cca

Browse files
committed
test: add service test with mocking
1 parent 592d7c4 commit 9081cca

File tree

8 files changed

+1198
-39
lines changed

8 files changed

+1198
-39
lines changed

apps/server/package.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@
8989
"**/*.(t|j)s"
9090
],
9191
"coverageDirectory": "../coverage",
92-
"testEnvironment": "node"
92+
"testEnvironment": "node",
93+
"moduleNameMapper": {
94+
"@src/(.*)$": "<rootDir>/$1",
95+
"@users/(.*)$": "<rootDir>/users/$1",
96+
"@sessions/(.*)$": "<rootDir>/sessions/$1",
97+
"@sessions-auth/(.*)$": "<rootDir>/sessions-auth/$1",
98+
"@questions/(.*)$": "<rootDir>/questions/$1",
99+
"@replies/(.*)$": "<rootDir>/replies/$1",
100+
"@common/(.*)$": "<rootDir>/common/$1",
101+
"@auth/(.*)$": "<rootDir>/auth/$1",
102+
"@upload/(.*)$": "<rootDir>/upload/$1",
103+
"@chats/(.*)$": "<rootDir>/chats/$1",
104+
"@socket/(.*)$": "<rootDir>/socket/$1",
105+
"@logger/(.*)$": "<rootDir>/logger/$1",
106+
"@prisma-alias/(.*)$": "<rootDir>/prisma/$1",
107+
"@main/(.*)$": "<rootDir>/main/$1"
108+
}
93109
}
94110
}

apps/server/src/chats/chats.repository.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,27 @@ export class ChatsRepository {
2424
throw DatabaseException.create('chat');
2525
}
2626
}
27+
async getChatsForInfiniteScroll(sessionId: string, count: number, chatId?: number) {
28+
try {
29+
return await this.prisma.chatting.findMany({
30+
where: {
31+
sessionId,
32+
...(chatId && { chattingId: { lt: chatId } }),
33+
},
34+
include: {
35+
createUserTokenEntity: {
36+
include: {
37+
user: true,
38+
},
39+
},
40+
},
41+
orderBy: {
42+
chattingId: 'desc',
43+
},
44+
take: count,
45+
});
46+
} catch (error) {
47+
throw new Error('Error retrieving chats from database');
48+
}
49+
}
2750
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
3+
import { ChatsRepository } from './chats.repository';
4+
import { ChatSaveDto, ChatsService } from './chats.service';
5+
6+
describe('ChatsService', () => {
7+
let service: ChatsService;
8+
let chatsRepository: jest.Mocked<ChatsRepository>;
9+
10+
beforeEach(async () => {
11+
const module: TestingModule = await Test.createTestingModule({
12+
providers: [
13+
ChatsService,
14+
{
15+
provide: ChatsRepository,
16+
useValue: {
17+
save: jest.fn(),
18+
getChatsForInfiniteScroll: jest.fn(),
19+
},
20+
},
21+
],
22+
}).compile();
23+
24+
service = module.get<ChatsService>(ChatsService);
25+
chatsRepository = module.get(ChatsRepository);
26+
});
27+
28+
it('should be defined', () => {
29+
expect(service).toBeDefined();
30+
});
31+
describe('saveChat', () => {
32+
it('should save the chat and return the saved data', async () => {
33+
const data: ChatSaveDto = { sessionId: '123', token: 'mockToken', body: 'Test message' };
34+
35+
const mockUser = {
36+
userId: 1,
37+
38+
password: 'hashedPassword',
39+
nickname: 'TestUser',
40+
createdAt: new Date('2024-01-01T00:00:00.000Z'),
41+
};
42+
43+
const savedChat = {
44+
chattingId: 1,
45+
sessionId: 'test-session',
46+
createUserToken: 'mockToken',
47+
body: 'Test chat message',
48+
createdAt: new Date('2024-01-01T00:00:00.000Z'),
49+
createUserTokenEntity: {
50+
user: mockUser,
51+
},
52+
};
53+
54+
chatsRepository.save.mockResolvedValue(savedChat);
55+
56+
const result = await service.saveChat(data);
57+
expect(chatsRepository.save).toHaveBeenCalledWith(data);
58+
expect(result).toEqual({
59+
chattingId: 1,
60+
nickname: 'TestUser',
61+
content: 'Test chat message',
62+
});
63+
});
64+
65+
it('should return "익명" if the user has no nickname', async () => {
66+
const data: ChatSaveDto = { sessionId: '123', token: 'mockToken', body: 'Test message' };
67+
68+
const savedChatWithNoNickname = {
69+
chattingId: 1,
70+
createUserTokenEntity: {
71+
user: {
72+
createdAt: new Date(),
73+
userId: 123,
74+
75+
password: 'password',
76+
nickname: null,
77+
},
78+
},
79+
createUserToken: 'token123',
80+
sessionId: 'session123',
81+
body: 'Test message',
82+
createdAt: new Date(),
83+
};
84+
85+
chatsRepository.save.mockResolvedValue(savedChatWithNoNickname);
86+
87+
const result = await service.saveChat(data);
88+
89+
expect(chatsRepository.save).toHaveBeenCalledWith(data);
90+
91+
expect(result).toEqual({
92+
chattingId: 1,
93+
nickname: '익명',
94+
content: 'Test message',
95+
});
96+
});
97+
});
98+
99+
describe('getChatsForInfiniteScroll', () => {
100+
it('should retrieve chats for infinite scroll', async () => {
101+
const sessionId = '123';
102+
const count = 10;
103+
const chatId = 5;
104+
105+
const chatData = [
106+
{
107+
chattingId: 10,
108+
createUserToken: 'token1',
109+
body: 'Message 1',
110+
createdAt: new Date(),
111+
sessionId: '123',
112+
createUserTokenEntity: {
113+
user: {
114+
userId: 1,
115+
createdAt: new Date(),
116+
117+
password: 'password1',
118+
nickname: 'User1',
119+
},
120+
token: 'token1',
121+
userId: 1,
122+
sessionId: '123',
123+
isHost: true,
124+
},
125+
},
126+
{
127+
chattingId: 9,
128+
createUserToken: 'token2',
129+
body: 'Message 2',
130+
createdAt: new Date(),
131+
sessionId: '123',
132+
createUserTokenEntity: {
133+
user: {
134+
userId: 2,
135+
createdAt: new Date(),
136+
137+
password: 'password2',
138+
nickname: 'User2',
139+
},
140+
token: 'token2',
141+
userId: 2,
142+
sessionId: '123',
143+
isHost: false,
144+
},
145+
},
146+
];
147+
148+
chatsRepository.getChatsForInfiniteScroll.mockResolvedValue(chatData);
149+
150+
const result = await service.getChatsForInfiniteScroll(sessionId, count, chatId);
151+
152+
expect(result).toEqual([
153+
{ chattingId: 10, nickname: 'User1', content: 'Message 1' },
154+
{ chattingId: 9, nickname: 'User2', content: 'Message 2' },
155+
]);
156+
});
157+
158+
it('should return "익명" if the user has no nickname', async () => {
159+
const sessionId = '123';
160+
const count = 10;
161+
const chatId = 5;
162+
163+
const chatData = [
164+
{
165+
chattingId: 10,
166+
body: 'Message 1',
167+
createUserToken: 'token1',
168+
createdAt: new Date(),
169+
sessionId: '123',
170+
createUserTokenEntity: {
171+
user: {
172+
userId: 1,
173+
createdAt: new Date(),
174+
175+
password: 'password',
176+
nickname: null,
177+
},
178+
token: 'token1',
179+
userId: 1,
180+
sessionId: '123',
181+
isHost: false,
182+
},
183+
},
184+
];
185+
186+
chatsRepository.getChatsForInfiniteScroll.mockResolvedValue(chatData);
187+
188+
const result = await service.getChatsForInfiniteScroll(sessionId, count, chatId);
189+
190+
expect(result).toEqual([{ chattingId: 10, nickname: '익명', content: 'Message 1' }]);
191+
});
192+
});
193+
});

apps/server/src/chats/chats.service.ts

Lines changed: 13 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ import { Injectable } from '@nestjs/common';
22

33
import { ChatsRepository } from './chats.repository';
44

5-
import { DatabaseException } from '@common/exceptions/resource.exception';
6-
import { PrismaService } from '@prisma-alias/prisma.service';
7-
85
export interface ChatSaveDto {
96
sessionId: string;
107
token: string;
@@ -13,10 +10,7 @@ export interface ChatSaveDto {
1310

1411
@Injectable()
1512
export class ChatsService {
16-
constructor(
17-
private readonly chatsRepository: ChatsRepository,
18-
private readonly prisma: PrismaService,
19-
) {}
13+
constructor(private readonly chatsRepository: ChatsRepository) {}
2014

2115
async saveChat(data: ChatSaveDto) {
2216
const chat = await this.chatsRepository.save(data);
@@ -25,36 +19,17 @@ export class ChatsService {
2519
}
2620

2721
async getChatsForInfiniteScroll(sessionId: string, count: number, chatId?: number) {
28-
try {
29-
const chats = await this.prisma.chatting.findMany({
30-
where: {
31-
sessionId,
32-
...(chatId && { chattingId: { lt: chatId } }),
33-
},
34-
include: {
35-
createUserTokenEntity: {
36-
include: {
37-
user: true,
38-
},
39-
},
40-
},
41-
orderBy: {
42-
chattingId: 'desc',
43-
},
44-
take: count,
45-
});
46-
return chats.map((x) => {
47-
const { createUserTokenEntity, chattingId, body: content } = x;
48-
const { user } = createUserTokenEntity;
49-
const nickname = user?.nickname || '익명';
50-
return {
51-
chattingId,
52-
nickname,
53-
content,
54-
};
55-
});
56-
} catch (error) {
57-
throw DatabaseException.read('chatting');
58-
}
22+
const chats = await this.chatsRepository.getChatsForInfiniteScroll(sessionId, count, chatId);
23+
24+
return chats.map((x) => {
25+
const { createUserTokenEntity, chattingId, body: content } = x;
26+
const { user } = createUserTokenEntity;
27+
const nickname = user?.nickname || '익명';
28+
return {
29+
chattingId,
30+
nickname,
31+
content,
32+
};
33+
});
5934
}
6035
}

0 commit comments

Comments
 (0)