Skip to content
This repository was archived by the owner on Jan 28, 2026. It is now read-only.

Commit e062c3c

Browse files
committed
test: Add unit tests for AchievementRepository and AchievementService to ensure functionality and error handling
1 parent e0ca0de commit e062c3c

2 files changed

Lines changed: 846 additions & 0 deletions

File tree

Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
import 'reflect-metadata';
2+
import { Test, TestingModule } from '@nestjs/testing';
3+
import { describe, it, expect, beforeEach, vi } from 'vitest';
4+
import { AchievementRepository } from './achievement.repository';
5+
import { DATABASE_CONNECTION } from '../database/database.module';
6+
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
7+
8+
describe('AchievementRepository', () => {
9+
let repository: AchievementRepository;
10+
let mockDb: NodePgDatabase;
11+
12+
const mockAchievement = {
13+
id: 1,
14+
title: 'Первое достижение',
15+
description: 'Описание достижения',
16+
icon: 'icon.png',
17+
rarity: 'common',
18+
questId: null,
19+
recordStatus: 'CREATED',
20+
createdAt: new Date(),
21+
updatedAt: new Date(),
22+
};
23+
24+
const mockQuest = {
25+
id: 1,
26+
title: 'Тестовый квест',
27+
recordStatus: 'CREATED',
28+
};
29+
30+
const mockUser = {
31+
id: 1,
32+
firstName: 'Иван',
33+
lastName: 'Иванов',
34+
email: 'ivan@example.com',
35+
recordStatus: 'CREATED',
36+
};
37+
38+
const mockUserAchievement = {
39+
id: 1,
40+
userId: 1,
41+
achievementId: 1,
42+
unlockedAt: new Date(),
43+
};
44+
45+
beforeEach(async () => {
46+
mockDb = {
47+
select: vi.fn().mockReturnThis(),
48+
from: vi.fn().mockReturnThis(),
49+
where: vi.fn().mockReturnThis(),
50+
insert: vi.fn().mockReturnThis(),
51+
values: vi.fn().mockReturnThis(),
52+
returning: vi.fn(),
53+
update: vi.fn().mockReturnThis(),
54+
set: vi.fn().mockReturnThis(),
55+
innerJoin: vi.fn().mockReturnThis(),
56+
} as unknown as NodePgDatabase;
57+
58+
const module: TestingModule = await Test.createTestingModule({
59+
providers: [
60+
AchievementRepository,
61+
{
62+
provide: DATABASE_CONNECTION,
63+
useValue: mockDb,
64+
},
65+
],
66+
}).compile();
67+
68+
repository = module.get<AchievementRepository>(AchievementRepository);
69+
});
70+
71+
describe('findByTitle', () => {
72+
it('should return achievement when found', async () => {
73+
(mockDb.select as any).mockReturnValue({
74+
from: vi.fn().mockReturnValue({
75+
where: vi.fn().mockResolvedValue([mockAchievement]),
76+
}),
77+
});
78+
79+
const result = await repository.findByTitle('Первое достижение');
80+
81+
expect(result).toEqual(mockAchievement);
82+
});
83+
84+
it('should return undefined when not found', async () => {
85+
(mockDb.select as any).mockReturnValue({
86+
from: vi.fn().mockReturnValue({
87+
where: vi.fn().mockResolvedValue([]),
88+
}),
89+
});
90+
91+
const result = await repository.findByTitle('Несуществующее');
92+
93+
expect(result).toBeUndefined();
94+
});
95+
});
96+
97+
describe('findById', () => {
98+
it('should return achievement when found', async () => {
99+
(mockDb.select as any).mockReturnValue({
100+
from: vi.fn().mockReturnValue({
101+
where: vi.fn().mockResolvedValue([mockAchievement]),
102+
}),
103+
});
104+
105+
const result = await repository.findById(1);
106+
107+
expect(result).toEqual(mockAchievement);
108+
});
109+
110+
it('should return undefined when not found', async () => {
111+
(mockDb.select as any).mockReturnValue({
112+
from: vi.fn().mockReturnValue({
113+
where: vi.fn().mockResolvedValue([]),
114+
}),
115+
});
116+
117+
const result = await repository.findById(999);
118+
119+
expect(result).toBeUndefined();
120+
});
121+
});
122+
123+
describe('findAll', () => {
124+
it('should return array of achievements', async () => {
125+
(mockDb.select as any).mockReturnValue({
126+
from: vi.fn().mockReturnValue({
127+
where: vi.fn().mockResolvedValue([mockAchievement]),
128+
}),
129+
});
130+
131+
const result = await repository.findAll();
132+
133+
expect(result).toEqual([mockAchievement]);
134+
});
135+
136+
it('should return empty array when no achievements', async () => {
137+
(mockDb.select as any).mockReturnValue({
138+
from: vi.fn().mockReturnValue({
139+
where: vi.fn().mockResolvedValue([]),
140+
}),
141+
});
142+
143+
const result = await repository.findAll();
144+
145+
expect(result).toEqual([]);
146+
});
147+
});
148+
149+
describe('create', () => {
150+
it('should create and return achievement', async () => {
151+
const createData = {
152+
title: 'Новое достижение',
153+
description: 'Описание',
154+
rarity: 'common',
155+
};
156+
157+
(mockDb.insert as any).mockReturnValue({
158+
values: vi.fn().mockReturnValue({
159+
returning: vi.fn().mockResolvedValue([mockAchievement]),
160+
}),
161+
});
162+
163+
const result = await repository.create(createData);
164+
165+
expect(result).toEqual(mockAchievement);
166+
});
167+
});
168+
169+
describe('update', () => {
170+
it('should update and return achievement', async () => {
171+
const updateData = {
172+
title: 'Обновленное название',
173+
};
174+
const updatedAchievement = { ...mockAchievement, ...updateData };
175+
176+
(mockDb.update as any).mockReturnValue({
177+
set: vi.fn().mockReturnValue({
178+
where: vi.fn().mockReturnValue({
179+
returning: vi.fn().mockResolvedValue([updatedAchievement]),
180+
}),
181+
}),
182+
});
183+
184+
const result = await repository.update(1, updateData);
185+
186+
expect(result).toEqual(updatedAchievement);
187+
});
188+
189+
it('should return undefined when achievement not found', async () => {
190+
(mockDb.update as any).mockReturnValue({
191+
set: vi.fn().mockReturnValue({
192+
where: vi.fn().mockReturnValue({
193+
returning: vi.fn().mockResolvedValue([]),
194+
}),
195+
}),
196+
});
197+
198+
const result = await repository.update(999, { title: 'Новое' });
199+
200+
expect(result).toBeUndefined();
201+
});
202+
});
203+
204+
describe('softDelete', () => {
205+
it('should soft delete and return achievement', async () => {
206+
const deletedAchievement = { ...mockAchievement, recordStatus: 'DELETED' };
207+
208+
(mockDb.update as any).mockReturnValue({
209+
set: vi.fn().mockReturnValue({
210+
where: vi.fn().mockReturnValue({
211+
returning: vi.fn().mockResolvedValue([deletedAchievement]),
212+
}),
213+
}),
214+
});
215+
216+
const result = await repository.softDelete(1);
217+
218+
expect(result).toEqual(deletedAchievement);
219+
});
220+
});
221+
222+
describe('findQuestById', () => {
223+
it('should return quest when found', async () => {
224+
(mockDb.select as any).mockReturnValue({
225+
from: vi.fn().mockReturnValue({
226+
where: vi.fn().mockResolvedValue([mockQuest]),
227+
}),
228+
});
229+
230+
const result = await repository.findQuestById(1);
231+
232+
expect(result).toEqual(mockQuest);
233+
});
234+
235+
it('should return undefined when not found', async () => {
236+
(mockDb.select as any).mockReturnValue({
237+
from: vi.fn().mockReturnValue({
238+
where: vi.fn().mockResolvedValue([]),
239+
}),
240+
});
241+
242+
const result = await repository.findQuestById(999);
243+
244+
expect(result).toBeUndefined();
245+
});
246+
});
247+
248+
describe('findUserById', () => {
249+
it('should return user when found', async () => {
250+
(mockDb.select as any).mockReturnValue({
251+
from: vi.fn().mockReturnValue({
252+
where: vi.fn().mockResolvedValue([mockUser]),
253+
}),
254+
});
255+
256+
const result = await repository.findUserById(1);
257+
258+
expect(result).toEqual(mockUser);
259+
});
260+
261+
it('should return undefined when not found', async () => {
262+
(mockDb.select as any).mockReturnValue({
263+
from: vi.fn().mockReturnValue({
264+
where: vi.fn().mockResolvedValue([]),
265+
}),
266+
});
267+
268+
const result = await repository.findUserById(999);
269+
270+
expect(result).toBeUndefined();
271+
});
272+
});
273+
274+
describe('findUserAchievement', () => {
275+
it('should return user achievement when found', async () => {
276+
(mockDb.select as any).mockReturnValue({
277+
from: vi.fn().mockReturnValue({
278+
where: vi.fn().mockResolvedValue([mockUserAchievement]),
279+
}),
280+
});
281+
282+
const result = await repository.findUserAchievement(1, 1);
283+
284+
expect(result).toEqual(mockUserAchievement);
285+
});
286+
287+
it('should return undefined when not found', async () => {
288+
(mockDb.select as any).mockReturnValue({
289+
from: vi.fn().mockReturnValue({
290+
where: vi.fn().mockResolvedValue([]),
291+
}),
292+
});
293+
294+
const result = await repository.findUserAchievement(1, 999);
295+
296+
expect(result).toBeUndefined();
297+
});
298+
});
299+
300+
describe('assignToUser', () => {
301+
it('should assign achievement to user and return result', async () => {
302+
(mockDb.insert as any).mockReturnValue({
303+
values: vi.fn().mockReturnValue({
304+
returning: vi.fn().mockResolvedValue([mockUserAchievement]),
305+
}),
306+
});
307+
308+
const result = await repository.assignToUser(1, 1);
309+
310+
expect(result).toEqual(mockUserAchievement);
311+
});
312+
});
313+
314+
describe('findUserAchievements', () => {
315+
it('should return user achievements with details', async () => {
316+
const userAchievementsWithDetails = [
317+
{
318+
id: 1,
319+
userId: 1,
320+
achievementId: 1,
321+
unlockedAt: new Date(),
322+
achievement: {
323+
id: 1,
324+
title: 'Первое достижение',
325+
description: 'Описание',
326+
icon: 'icon.png',
327+
rarity: 'common',
328+
questId: null,
329+
createdAt: new Date(),
330+
updatedAt: new Date(),
331+
},
332+
},
333+
];
334+
335+
(mockDb.select as any).mockReturnValue({
336+
from: vi.fn().mockReturnValue({
337+
innerJoin: vi.fn().mockReturnValue({
338+
where: vi.fn().mockResolvedValue(userAchievementsWithDetails),
339+
}),
340+
}),
341+
});
342+
343+
const result = await repository.findUserAchievements(1);
344+
345+
expect(result).toEqual(userAchievementsWithDetails);
346+
});
347+
348+
it('should return empty array when user has no achievements', async () => {
349+
(mockDb.select as any).mockReturnValue({
350+
from: vi.fn().mockReturnValue({
351+
innerJoin: vi.fn().mockReturnValue({
352+
where: vi.fn().mockResolvedValue([]),
353+
}),
354+
}),
355+
});
356+
357+
const result = await repository.findUserAchievements(1);
358+
359+
expect(result).toEqual([]);
360+
});
361+
});
362+
});
363+

0 commit comments

Comments
 (0)