@volontariapp/domain-user 2.3.5 → 2.3.7-snap-41ca1a9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/entities/user.entity.d.ts +3 -1
  3. package/dist/entities/user.entity.d.ts.map +1 -1
  4. package/dist/entities/user.entity.js +41 -0
  5. package/dist/entities/user.entity.js.map +1 -1
  6. package/dist/models/mapper.d.ts +2 -0
  7. package/dist/models/mapper.d.ts.map +1 -0
  8. package/dist/models/mapper.js +36 -0
  9. package/dist/models/mapper.js.map +1 -0
  10. package/dist/models/user.model.js +3 -3
  11. package/dist/models/user.model.js.map +1 -1
  12. package/dist/repositories/index.d.ts +4 -0
  13. package/dist/repositories/index.d.ts.map +1 -0
  14. package/dist/repositories/index.js +4 -0
  15. package/dist/repositories/index.js.map +1 -0
  16. package/dist/repositories/interfaces/badge.repository.d.ts +11 -0
  17. package/dist/repositories/interfaces/badge.repository.d.ts.map +1 -0
  18. package/dist/repositories/interfaces/badge.repository.js +2 -0
  19. package/dist/repositories/interfaces/badge.repository.js.map +1 -0
  20. package/dist/repositories/interfaces/index.d.ts +3 -0
  21. package/dist/repositories/interfaces/index.d.ts.map +1 -0
  22. package/dist/repositories/interfaces/index.js +3 -0
  23. package/dist/repositories/interfaces/index.js.map +1 -0
  24. package/dist/repositories/interfaces/user.repository.d.ts +16 -0
  25. package/dist/repositories/interfaces/user.repository.d.ts.map +1 -0
  26. package/dist/repositories/interfaces/user.repository.js +2 -0
  27. package/dist/repositories/interfaces/user.repository.js.map +1 -0
  28. package/dist/repositories/postgres-badge.repository.d.ts +12 -0
  29. package/dist/repositories/postgres-badge.repository.d.ts.map +1 -0
  30. package/dist/repositories/postgres-badge.repository.js +38 -0
  31. package/dist/repositories/postgres-badge.repository.js.map +1 -0
  32. package/dist/repositories/postgres-user.repository.d.ts +23 -0
  33. package/dist/repositories/postgres-user.repository.d.ts.map +1 -0
  34. package/dist/repositories/postgres-user.repository.js +94 -0
  35. package/dist/repositories/postgres-user.repository.js.map +1 -0
  36. package/dist/services/auth.service.d.ts +13 -0
  37. package/dist/services/auth.service.d.ts.map +1 -0
  38. package/dist/services/auth.service.js +95 -0
  39. package/dist/services/auth.service.js.map +1 -0
  40. package/dist/services/badge.service.d.ts +17 -0
  41. package/dist/services/badge.service.d.ts.map +1 -0
  42. package/dist/services/badge.service.js +152 -0
  43. package/dist/services/badge.service.js.map +1 -0
  44. package/dist/services/user.service.d.ts +22 -0
  45. package/dist/services/user.service.d.ts.map +1 -0
  46. package/dist/services/user.service.js +196 -0
  47. package/dist/services/user.service.js.map +1 -0
  48. package/dist/test/__test-utils__/factories/badge.factory.d.ts +19 -0
  49. package/dist/test/__test-utils__/factories/badge.factory.d.ts.map +1 -0
  50. package/dist/test/__test-utils__/factories/badge.factory.js +27 -0
  51. package/dist/test/__test-utils__/factories/badge.factory.js.map +1 -0
  52. package/dist/test/__test-utils__/factories/commands.factory.d.ts +16 -0
  53. package/dist/test/__test-utils__/factories/commands.factory.d.ts.map +1 -0
  54. package/dist/test/__test-utils__/factories/commands.factory.js +12 -0
  55. package/dist/test/__test-utils__/factories/commands.factory.js.map +1 -0
  56. package/dist/test/__test-utils__/factories/user.factory.d.ts +8 -0
  57. package/dist/test/__test-utils__/factories/user.factory.d.ts.map +1 -0
  58. package/dist/test/__test-utils__/factories/user.factory.js +42 -0
  59. package/dist/test/__test-utils__/factories/user.factory.js.map +1 -0
  60. package/dist/test/__test-utils__/mocks/badge.repository.mock.d.ts +4 -0
  61. package/dist/test/__test-utils__/mocks/badge.repository.mock.d.ts.map +1 -0
  62. package/dist/test/__test-utils__/mocks/badge.repository.mock.js +11 -0
  63. package/dist/test/__test-utils__/mocks/badge.repository.mock.js.map +1 -0
  64. package/dist/test/__test-utils__/mocks/user.repository.mock.d.ts +4 -0
  65. package/dist/test/__test-utils__/mocks/user.repository.mock.d.ts.map +1 -0
  66. package/dist/test/__test-utils__/mocks/user.repository.mock.js +16 -0
  67. package/dist/test/__test-utils__/mocks/user.repository.mock.js.map +1 -0
  68. package/dist/test/data-source.d.ts +8 -0
  69. package/dist/test/data-source.d.ts.map +1 -0
  70. package/dist/test/data-source.js +36 -0
  71. package/dist/test/data-source.js.map +1 -0
  72. package/dist/test/integration/postgres-badge.repository.int.spec.d.ts +2 -0
  73. package/dist/test/integration/postgres-badge.repository.int.spec.d.ts.map +1 -0
  74. package/dist/test/integration/postgres-badge.repository.int.spec.js +129 -0
  75. package/dist/test/integration/postgres-badge.repository.int.spec.js.map +1 -0
  76. package/dist/test/integration/postgres-user.repository.int.spec.d.ts +2 -0
  77. package/dist/test/integration/postgres-user.repository.int.spec.d.ts.map +1 -0
  78. package/dist/test/integration/postgres-user.repository.int.spec.js +222 -0
  79. package/dist/test/integration/postgres-user.repository.int.spec.js.map +1 -0
  80. package/dist/test/migrations/1776334421317-InitialUserSchema.d.ts +7 -0
  81. package/dist/test/migrations/1776334421317-InitialUserSchema.d.ts.map +1 -0
  82. package/dist/test/migrations/1776334421317-InitialUserSchema.js +58 -0
  83. package/dist/test/migrations/1776334421317-InitialUserSchema.js.map +1 -0
  84. package/dist/test/setup.d.ts +2 -0
  85. package/dist/test/setup.d.ts.map +1 -0
  86. package/dist/test/setup.js +2 -0
  87. package/dist/test/setup.js.map +1 -0
  88. package/dist/test/unit/auth.service.unit.spec.d.ts +2 -0
  89. package/dist/test/unit/auth.service.unit.spec.d.ts.map +1 -0
  90. package/dist/test/unit/auth.service.unit.spec.js +233 -0
  91. package/dist/test/unit/auth.service.unit.spec.js.map +1 -0
  92. package/dist/test/unit/badge.service.unit.spec.d.ts +2 -0
  93. package/dist/test/unit/badge.service.unit.spec.d.ts.map +1 -0
  94. package/dist/test/unit/badge.service.unit.spec.js +137 -0
  95. package/dist/test/unit/badge.service.unit.spec.js.map +1 -0
  96. package/dist/test/unit/mapper.unit.spec.d.ts +2 -0
  97. package/dist/test/unit/mapper.unit.spec.d.ts.map +1 -0
  98. package/dist/test/unit/mapper.unit.spec.js +358 -0
  99. package/dist/test/unit/mapper.unit.spec.js.map +1 -0
  100. package/dist/test/unit/user.service.unit.spec.d.ts +2 -0
  101. package/dist/test/unit/user.service.unit.spec.d.ts.map +1 -0
  102. package/dist/test/unit/user.service.unit.spec.js +496 -0
  103. package/dist/test/unit/user.service.unit.spec.js.map +1 -0
  104. package/dist/value-objects/auth.vo.d.ts +26 -0
  105. package/dist/value-objects/auth.vo.d.ts.map +1 -0
  106. package/dist/value-objects/auth.vo.js +41 -0
  107. package/dist/value-objects/auth.vo.js.map +1 -0
  108. package/dist/value-objects/badge.vo.d.ts +28 -0
  109. package/dist/value-objects/badge.vo.d.ts.map +1 -0
  110. package/dist/value-objects/badge.vo.js +37 -0
  111. package/dist/value-objects/badge.vo.js.map +1 -0
  112. package/dist/value-objects/index.d.ts +4 -0
  113. package/dist/value-objects/index.d.ts.map +1 -0
  114. package/dist/value-objects/index.js +4 -0
  115. package/dist/value-objects/index.js.map +1 -0
  116. package/dist/value-objects/user.vo.d.ts +40 -0
  117. package/dist/value-objects/user.vo.d.ts.map +1 -0
  118. package/dist/value-objects/user.vo.js +53 -0
  119. package/dist/value-objects/user.vo.js.map +1 -0
  120. package/package.json +13 -3
@@ -0,0 +1,233 @@
1
+ import 'reflect-metadata';
2
+ import { jest, describe, it, expect, beforeEach, afterEach } from '@jest/globals';
3
+ import { AuthService } from '../../services/auth.service.js';
4
+ import { Logger } from '@volontariapp/logger';
5
+ import { createUserRepositoryMock } from '../__test-utils__/mocks/user.repository.mock.js';
6
+ import { UserFactory } from '../__test-utils__/factories/user.factory.js';
7
+ import { CommandsFactory } from '../__test-utils__/factories/commands.factory.js';
8
+ import { hashPassword } from '@volontariapp/crypto';
9
+ describe('AuthService (Unit)', () => {
10
+ let service;
11
+ let mockRepository;
12
+ let jwtServiceMock;
13
+ let loggerWarnSpy;
14
+ let loggerErrorSpy;
15
+ beforeEach(() => {
16
+ mockRepository = createUserRepositoryMock();
17
+ jwtServiceMock = {
18
+ signAccessToken: jest.fn().mockResolvedValue('access-token'),
19
+ signRefreshToken: jest
20
+ .fn()
21
+ .mockResolvedValue('refresh-token'),
22
+ };
23
+ service = new AuthService(mockRepository, jwtServiceMock);
24
+ loggerWarnSpy = jest
25
+ .spyOn(Logger.prototype, 'warn')
26
+ .mockImplementation(() => undefined);
27
+ loggerErrorSpy = jest
28
+ .spyOn(Logger.prototype, 'error')
29
+ .mockImplementation(() => undefined);
30
+ });
31
+ afterEach(() => {
32
+ jest.restoreAllMocks();
33
+ });
34
+ describe('signUp()', () => {
35
+ describe('HAPPY PATH: User registered successfully', () => {
36
+ it('should create user and return tokens when valid command provided', async () => {
37
+ const command = CommandsFactory.buildSignUpCommand({
38
+ email: 'neworg@example.com',
39
+ password: 'SecurePass123!',
40
+ pseudo: 'neworg',
41
+ });
42
+ const createdUser = UserFactory.build({
43
+ email: 'neworg@example.com',
44
+ pseudo: 'neworg',
45
+ });
46
+ mockRepository.findByEmail.mockResolvedValue(null);
47
+ mockRepository.createWithHashedPassword.mockResolvedValue(createdUser);
48
+ const result = await service.signUp(command);
49
+ expect(result.auth.accessToken).toBe('access-token');
50
+ expect(result.auth.refreshToken).toBe('refresh-token');
51
+ expect(result.user).toEqual(createdUser);
52
+ expect(mockRepository.findByEmail).toHaveBeenCalledWith('neworg@example.com');
53
+ expect(mockRepository.createWithHashedPassword).toHaveBeenCalledTimes(1);
54
+ expect(jwtServiceMock.signAccessToken).toHaveBeenCalled();
55
+ });
56
+ it('should create organization user when RNA is provided', async () => {
57
+ const command = CommandsFactory.buildSignUpCommand({ rna: 'W123456789' });
58
+ const createdUser = UserFactory.build({ rna: 'W123456789' });
59
+ mockRepository.findByEmail.mockResolvedValue(null);
60
+ mockRepository.createWithHashedPassword.mockResolvedValue(createdUser);
61
+ const result = await service.signUp(command);
62
+ expect(result.auth.accessToken).toBe('access-token');
63
+ expect(result.auth.refreshToken).toBe('refresh-token');
64
+ expect(createdUser.rna).toBe('W123456789');
65
+ expect(mockRepository.createWithHashedPassword).toHaveBeenCalled();
66
+ });
67
+ it('should create volunteer user when no RNA is provided', async () => {
68
+ const command = CommandsFactory.buildSignUpCommand({});
69
+ const createdUser = UserFactory.build({ rna: undefined });
70
+ mockRepository.findByEmail.mockResolvedValue(null);
71
+ mockRepository.createWithHashedPassword.mockResolvedValue(createdUser);
72
+ const result = await service.signUp(command);
73
+ expect(result.auth.accessToken).toBe('access-token');
74
+ expect(result.auth.refreshToken).toBe('refresh-token');
75
+ expect(createdUser.rna).toBeUndefined();
76
+ expect(jwtServiceMock.signAccessToken).toHaveBeenCalled();
77
+ });
78
+ });
79
+ describe('SAD PATH: User already exists', () => {
80
+ it('should throw CONFLICT error when email is already registered', async () => {
81
+ const command = CommandsFactory.buildSignUpCommand({ email: 'existing@example.com' });
82
+ const existingUser = UserFactory.build({ email: 'existing@example.com' });
83
+ mockRepository.findByEmail.mockResolvedValue(existingUser);
84
+ await expect(service.signUp(command)).rejects.toMatchObject({
85
+ code: 'CONFLICT',
86
+ });
87
+ expect(loggerWarnSpy).toHaveBeenCalled();
88
+ expect(mockRepository.createWithHashedPassword).not.toHaveBeenCalled();
89
+ });
90
+ });
91
+ describe('SAD PATH: Validation fails', () => {
92
+ it('should throw BAD_REQUEST when RNA format is invalid', async () => {
93
+ const command = CommandsFactory.buildSignUpCommand({ rna: 'INVALID-RNA' });
94
+ mockRepository.findByEmail.mockResolvedValue(null);
95
+ await expect(service.signUp(command)).rejects.toMatchObject({
96
+ code: 'BAD_REQUEST',
97
+ });
98
+ expect(mockRepository.createWithHashedPassword).not.toHaveBeenCalled();
99
+ });
100
+ it('should throw BAD_REQUEST when RNA lacks W prefix', async () => {
101
+ const command = CommandsFactory.buildSignUpCommand({ rna: '123456789' });
102
+ mockRepository.findByEmail.mockResolvedValue(null);
103
+ await expect(service.signUp(command)).rejects.toMatchObject({
104
+ code: 'BAD_REQUEST',
105
+ });
106
+ expect(mockRepository.createWithHashedPassword).not.toHaveBeenCalled();
107
+ });
108
+ });
109
+ describe('ERROR HANDLING: Duplicate email (DB constraint)', () => {
110
+ it('should throw CONFLICT error on unique constraint violation (code 23505)', async () => {
111
+ const command = CommandsFactory.buildSignUpCommand({ email: 'duplicate@example.com' });
112
+ mockRepository.findByEmail.mockResolvedValue(null);
113
+ const dbError = new Error('unique constraint violation');
114
+ Object.defineProperty(dbError, 'code', { value: '23505' });
115
+ mockRepository.createWithHashedPassword.mockRejectedValue(dbError);
116
+ await expect(service.signUp(command)).rejects.toMatchObject({
117
+ code: 'CONFLICT',
118
+ });
119
+ });
120
+ });
121
+ describe('ERROR HANDLING: Database failures', () => {
122
+ it('should throw DATABASE_ERROR on unexpected repository error', async () => {
123
+ const command = CommandsFactory.buildSignUpCommand();
124
+ mockRepository.findByEmail.mockResolvedValue(null);
125
+ mockRepository.createWithHashedPassword.mockRejectedValue(new Error('Connection timeout'));
126
+ await expect(service.signUp(command)).rejects.toMatchObject({
127
+ code: 'DATABASE_ERROR',
128
+ });
129
+ expect(loggerErrorSpy).toHaveBeenCalled();
130
+ });
131
+ it('should log error details when repository fails', async () => {
132
+ const command = CommandsFactory.buildSignUpCommand();
133
+ mockRepository.findByEmail.mockResolvedValue(null);
134
+ const dbError = new Error('Network unreachable');
135
+ mockRepository.createWithHashedPassword.mockRejectedValue(dbError);
136
+ await service.signUp(command).catch(() => { });
137
+ expect(loggerErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Error while creating user'));
138
+ });
139
+ });
140
+ });
141
+ describe('logIn()', () => {
142
+ describe('HAPPY PATH: User authenticated successfully', () => {
143
+ it('should return tokens when credentials are valid', async () => {
144
+ const command = CommandsFactory.buildLoginCommand({
145
+ email: 'user@example.com',
146
+ password: 'CorrectPassword123!',
147
+ });
148
+ const user = UserFactory.build({ email: 'user@example.com' });
149
+ const passwordHash = hashPassword('CorrectPassword123!');
150
+ mockRepository.findByEmail.mockResolvedValue(user);
151
+ mockRepository.findPasswordHashByEmail.mockResolvedValue(passwordHash);
152
+ const result = await service.logIn(command);
153
+ expect(result.accessToken).toBe('access-token');
154
+ expect(result.refreshToken).toBe('refresh-token');
155
+ expect(mockRepository.findByEmail).toHaveBeenCalledWith('user@example.com');
156
+ expect(mockRepository.findPasswordHashByEmail).toHaveBeenCalledWith('user@example.com');
157
+ expect(jwtServiceMock.signAccessToken).toHaveBeenCalled();
158
+ });
159
+ });
160
+ describe('SAD PATH: User not found', () => {
161
+ it('should throw NOT_FOUND when user does not exist', async () => {
162
+ const command = CommandsFactory.buildLoginCommand({ email: 'nonexistent@example.com' });
163
+ mockRepository.findByEmail.mockResolvedValue(null);
164
+ await expect(service.logIn(command)).rejects.toMatchObject({
165
+ code: 'NOT_FOUND',
166
+ });
167
+ expect(loggerWarnSpy).toHaveBeenCalled();
168
+ expect(mockRepository.findPasswordHashByEmail).not.toHaveBeenCalled();
169
+ });
170
+ });
171
+ describe('SAD PATH: Invalid credentials', () => {
172
+ it('should throw NOT_FOUND when password hash is missing', async () => {
173
+ const command = CommandsFactory.buildLoginCommand({ email: 'user@example.com' });
174
+ const user = UserFactory.build({ email: 'user@example.com' });
175
+ mockRepository.findByEmail.mockResolvedValue(user);
176
+ mockRepository.findPasswordHashByEmail.mockResolvedValue(null);
177
+ await expect(service.logIn(command)).rejects.toMatchObject({
178
+ code: 'NOT_FOUND',
179
+ });
180
+ expect(loggerWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid password attempt'));
181
+ });
182
+ it('should throw NOT_FOUND when password is incorrect', async () => {
183
+ const command = CommandsFactory.buildLoginCommand({
184
+ email: 'user@example.com',
185
+ password: 'WrongPassword',
186
+ });
187
+ const user = UserFactory.build({ email: 'user@example.com' });
188
+ const correctPasswordHash = hashPassword('CorrectPassword');
189
+ mockRepository.findByEmail.mockResolvedValue(user);
190
+ mockRepository.findPasswordHashByEmail.mockResolvedValue(correctPasswordHash);
191
+ await expect(service.logIn(command)).rejects.toMatchObject({
192
+ code: 'NOT_FOUND',
193
+ });
194
+ expect(loggerWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Invalid password attempt'));
195
+ });
196
+ it('should return same error type for both missing user and wrong password', async () => {
197
+ const nonExistentCommand = CommandsFactory.buildLoginCommand({
198
+ email: 'nonexistent@example.com',
199
+ });
200
+ const wrongPasswordCommand = CommandsFactory.buildLoginCommand({
201
+ email: 'user@example.com',
202
+ password: 'WrongPassword',
203
+ });
204
+ const user = UserFactory.build({ email: 'user@example.com' });
205
+ const correctHash = hashPassword('CorrectPassword');
206
+ mockRepository.findByEmail.mockResolvedValueOnce(null);
207
+ await expect(service.logIn(nonExistentCommand)).rejects.toMatchObject({
208
+ code: 'NOT_FOUND',
209
+ });
210
+ mockRepository.findByEmail.mockResolvedValueOnce(user);
211
+ mockRepository.findPasswordHashByEmail.mockResolvedValue(correctHash);
212
+ await expect(service.logIn(wrongPasswordCommand)).rejects.toMatchObject({
213
+ code: 'NOT_FOUND',
214
+ });
215
+ });
216
+ });
217
+ describe('ERROR HANDLING: Database failures', () => {
218
+ it('should bubble up error when finding user fails', async () => {
219
+ const command = CommandsFactory.buildLoginCommand();
220
+ mockRepository.findByEmail.mockRejectedValue(new Error('Connection failed'));
221
+ await expect(service.logIn(command)).rejects.toThrow('Connection failed');
222
+ });
223
+ it('should bubble up error when finding password hash fails', async () => {
224
+ const command = CommandsFactory.buildLoginCommand();
225
+ const user = UserFactory.build();
226
+ mockRepository.findByEmail.mockResolvedValue(user);
227
+ mockRepository.findPasswordHashByEmail.mockRejectedValue(new Error('DB lost'));
228
+ await expect(service.logIn(command)).rejects.toThrow('DB lost');
229
+ });
230
+ });
231
+ });
232
+ });
233
+ //# sourceMappingURL=auth.service.unit.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.service.unit.spec.js","sourceRoot":"","sources":["../../../src/test/unit/auth.service.unit.spec.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,wBAAwB,EAAE,MAAM,iDAAiD,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,MAAM,6CAA6C,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,iDAAiD,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIpD,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAI,OAAoB,CAAC;IACzB,IAAI,cAA4C,CAAC;IACjD,IAAI,cAAuC,CAAC;IAC5C,IAAI,aAA4D,CAAC;IACjE,IAAI,cAA6D,CAAC;IAElE,UAAU,CAAC,GAAG,EAAE;QACd,cAAc,GAAG,wBAAwB,EAAE,CAAC;QAE5C,cAAc,GAAG;YACf,eAAe,EAAE,IAAI,CAAC,EAAE,EAAiC,CAAC,iBAAiB,CAAC,cAAc,CAAC;YAC3F,gBAAgB,EAAE,IAAI;iBACnB,EAAE,EAAkC;iBACpC,iBAAiB,CAAC,eAAe,CAAC;SACA,CAAC;QAExC,OAAO,GAAG,IAAI,WAAW,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAE1D,aAAa,GAAG,IAAI;aACjB,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC;aAC/B,kBAAkB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAU,CAAC;QAChD,cAAc,GAAG,IAAI;aAClB,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;aAChC,kBAAkB,CAAC,GAAG,EAAE,CAAC,SAAS,CAAU,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,eAAe,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IAKH,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;YACxD,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;gBAEhF,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC;oBACjD,KAAK,EAAE,oBAAoB;oBAC3B,QAAQ,EAAE,gBAAgB;oBAC1B,MAAM,EAAE,QAAQ;iBACjB,CAAC,CAAC;gBACH,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC;oBACpC,KAAK,EAAE,oBAAoB;oBAC3B,MAAM,EAAE,QAAQ;iBACjB,CAAC,CAAC;gBACH,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBAGvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAG7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBACvD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;gBACzC,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,oBAAoB,CAAC,CAAC;gBAC9E,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;gBACzE,MAAM,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC5D,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;gBAEpE,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC1E,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC7D,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBAGvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAG7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBACvD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC3C,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACrE,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;gBAEpE,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;gBACvD,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC;gBAC1D,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBAGvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAG7C,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBACvD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,CAAC;gBACxC,MAAM,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC5D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;YAC7C,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;gBAE5E,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;gBACtF,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;gBAC1E,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;gBAG3D,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBAC1D,IAAI,EAAE,UAAU;iBACjB,CAAC,CAAC;gBACH,MAAM,CAAC,aAAa,CAAC,CAAC,gBAAgB,EAAE,CAAC;gBACzC,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACzE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;YAC1C,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;gBAEnE,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;gBAC3E,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAGnD,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBAC1D,IAAI,EAAE,aAAa;iBACpB,CAAC,CAAC;gBACH,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACzE,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;gBAEhE,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;gBACzE,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAGnD,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBAC1D,IAAI,EAAE,aAAa;iBACpB,CAAC,CAAC;gBACH,MAAM,CAAC,cAAc,CAAC,wBAAwB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACzE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,iDAAiD,EAAE,GAAG,EAAE;YAC/D,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;gBAEvF,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;gBACvF,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;gBACzD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC3D,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAGnE,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBAC1D,IAAI,EAAE,UAAU;iBACjB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;YACjD,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;gBAE1E,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,EAAE,CAAC;gBACrD,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;gBAG3F,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBAC1D,IAAI,EAAE,gBAAgB;iBACvB,CAAC,CAAC;gBACH,MAAM,CAAC,cAAc,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC5C,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;gBAE9D,MAAM,OAAO,GAAG,eAAe,CAAC,kBAAkB,EAAE,CAAC;gBACrD,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;gBACjD,cAAc,CAAC,wBAAwB,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;gBAGnE,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAG9C,MAAM,CAAC,cAAc,CAAC,CAAC,oBAAoB,CACzC,MAAM,CAAC,gBAAgB,CAAC,2BAA2B,CAAC,CACrD,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAKH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,QAAQ,CAAC,6CAA6C,EAAE,GAAG,EAAE;YAC3D,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;gBAE/D,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,CAAC;oBAChD,KAAK,EAAE,kBAAkB;oBACzB,QAAQ,EAAE,qBAAqB;iBAChC,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC9D,MAAM,YAAY,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;gBACzD,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;gBAGvE,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAG5C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBAChD,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAClD,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;gBAC5E,MAAM,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;gBACxF,MAAM,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,gBAAgB,EAAE,CAAC;YAC5D,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;YACxC,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;gBAE/D,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;gBACxF,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAGnD,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBACzD,IAAI,EAAE,WAAW;iBAClB,CAAC,CAAC;gBACH,MAAM,CAAC,aAAa,CAAC,CAAC,gBAAgB,EAAE,CAAC;gBACzC,MAAM,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YACxE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;YAC7C,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;gBAEpE,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBACjF,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC9D,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAG/D,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBACzD,IAAI,EAAE,WAAW;iBAClB,CAAC,CAAC;gBACH,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACxC,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CACpD,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;gBAEjE,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,CAAC;oBAChD,KAAK,EAAE,kBAAkB;oBACzB,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC9D,MAAM,mBAAmB,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;gBAC5D,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;gBAG9E,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBACzD,IAAI,EAAE,WAAW;iBAClB,CAAC,CAAC;gBACH,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACxC,MAAM,CAAC,gBAAgB,CAAC,0BAA0B,CAAC,CACpD,CAAC;YACJ,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;gBAEtF,MAAM,kBAAkB,GAAG,eAAe,CAAC,iBAAiB,CAAC;oBAC3D,KAAK,EAAE,yBAAyB;iBACjC,CAAC,CAAC;gBACH,MAAM,oBAAoB,GAAG,eAAe,CAAC,iBAAiB,CAAC;oBAC7D,KAAK,EAAE,kBAAkB;oBACzB,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CAAC;gBACH,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC9D,MAAM,WAAW,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;gBAGpD,cAAc,CAAC,WAAW,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBACvD,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBACpE,IAAI,EAAE,WAAW;iBAClB,CAAC,CAAC;gBAEH,cAAc,CAAC,WAAW,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;gBACvD,cAAc,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;gBACtE,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;oBACtE,IAAI,EAAE,WAAW;iBAClB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,QAAQ,CAAC,mCAAmC,EAAE,GAAG,EAAE;YACjD,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;gBAE9D,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,EAAE,CAAC;gBACpD,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBAG7E,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAC5E,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;gBAEvE,MAAM,OAAO,GAAG,eAAe,CAAC,iBAAiB,EAAE,CAAC;gBACpD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC;gBACjC,cAAc,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBACnD,cAAc,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBAG/E,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAClE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=badge.service.unit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.service.unit.spec.d.ts","sourceRoot":"","sources":["../../../src/test/unit/badge.service.unit.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,137 @@
1
+ import { describe, it, expect, beforeEach } from '@jest/globals';
2
+ import { BadgeService } from '../../services/badge.service.js';
3
+ import { BadgeFactory } from '../__test-utils__/factories/badge.factory.js';
4
+ import { createBadgeRepositoryMock } from '../__test-utils__/mocks/badge.repository.mock.js';
5
+ import { BadgeId, BadgeSlug, UpdateBadgeInput } from '../../value-objects/index.js';
6
+ describe('BadgeService (Unit)', () => {
7
+ let service;
8
+ let mockRepository;
9
+ beforeEach(() => {
10
+ mockRepository = createBadgeRepositoryMock();
11
+ service = new BadgeService(mockRepository);
12
+ });
13
+ describe('findById()', () => {
14
+ it('should return badge when found', async () => {
15
+ const badge = BadgeFactory.build({ id: 'b-1' });
16
+ mockRepository.findById.mockResolvedValue(badge);
17
+ const result = await service.findById(new BadgeId('b-1'));
18
+ expect(result).toEqual(badge);
19
+ expect(mockRepository.findById.mock.calls).toEqual([['b-1']]);
20
+ });
21
+ it('should throw BADGE_NOT_FOUND when not found', async () => {
22
+ mockRepository.findById.mockResolvedValue(null);
23
+ await expect(service.findById(new BadgeId('missing'))).rejects.toMatchObject({
24
+ code: 'NOT_FOUND',
25
+ });
26
+ });
27
+ it('should throw DATABASE_ERROR when repository throws', async () => {
28
+ mockRepository.findById.mockRejectedValue(new Error('fail'));
29
+ await expect(service.findById(new BadgeId('b-1'))).rejects.toMatchObject({
30
+ code: 'DATABASE_ERROR',
31
+ });
32
+ });
33
+ });
34
+ describe('findBySlug()', () => {
35
+ it('should return badge when found by slug', async () => {
36
+ const badge = BadgeFactory.build({ slug: 's-1' });
37
+ mockRepository.findBySlug.mockResolvedValue(badge);
38
+ const result = await service.findBySlug(new BadgeSlug('s-1'));
39
+ expect(result).toEqual(badge);
40
+ expect(mockRepository.findBySlug.mock.calls).toEqual([['s-1']]);
41
+ });
42
+ it('should throw BADGE_NOT_FOUND when missing', async () => {
43
+ mockRepository.findBySlug.mockResolvedValue(null);
44
+ await expect(service.findBySlug(new BadgeSlug('missing'))).rejects.toMatchObject({
45
+ code: 'NOT_FOUND',
46
+ });
47
+ });
48
+ });
49
+ describe('findAll()', () => {
50
+ it('should return all badges', async () => {
51
+ const badges = BadgeFactory.buildMany(3);
52
+ mockRepository.findAll.mockResolvedValue(badges);
53
+ const result = await service.findAll();
54
+ expect(result).toEqual(badges);
55
+ });
56
+ it('should throw DATABASE_ERROR when repository fails', async () => {
57
+ mockRepository.findAll.mockRejectedValue(new Error('fail'));
58
+ await expect(service.findAll()).rejects.toMatchObject({ code: 'DATABASE_ERROR' });
59
+ });
60
+ });
61
+ describe('findManyByIds()', () => {
62
+ it('should return badges by ids', async () => {
63
+ const badges = BadgeFactory.buildMany(2);
64
+ mockRepository.findManyByIds.mockResolvedValue(badges);
65
+ const result = await service.findManyByIds([new BadgeId('a'), new BadgeId('b')]);
66
+ expect(result).toEqual(badges);
67
+ expect(mockRepository.findManyByIds.mock.calls).toEqual([[['a', 'b']]]);
68
+ });
69
+ it('should throw DATABASE_ERROR when repository fails', async () => {
70
+ mockRepository.findManyByIds.mockRejectedValue(new Error('fail'));
71
+ await expect(service.findManyByIds([new BadgeId('a')])).rejects.toMatchObject({
72
+ code: 'DATABASE_ERROR',
73
+ });
74
+ });
75
+ });
76
+ describe('create()', () => {
77
+ it('should create and return badge', async () => {
78
+ const input = BadgeFactory.buildInput();
79
+ const created = BadgeFactory.build({
80
+ name: input.name,
81
+ slug: input.slug,
82
+ description: input.description,
83
+ });
84
+ mockRepository.create.mockResolvedValue(created);
85
+ const result = await service.create(input);
86
+ expect(result).toEqual(created);
87
+ expect(mockRepository.create).toHaveBeenCalledTimes(1);
88
+ });
89
+ it('should throw BADGE_ALREADY_EXISTS on duplicate slug', async () => {
90
+ const input = BadgeFactory.buildInput();
91
+ mockRepository.create.mockRejectedValue({ code: '23505' });
92
+ await expect(service.create(input)).rejects.toMatchObject({ code: 'CONFLICT' });
93
+ });
94
+ it('should throw DATABASE_ERROR when repository fails', async () => {
95
+ const input = BadgeFactory.buildInput();
96
+ mockRepository.create.mockRejectedValue(new Error('fail'));
97
+ await expect(service.create(input)).rejects.toMatchObject({ code: 'DATABASE_ERROR' });
98
+ });
99
+ });
100
+ describe('update()', () => {
101
+ it('should update and return badge', async () => {
102
+ const updated = BadgeFactory.build({ id: 'b-1', name: 'New' });
103
+ mockRepository.update.mockResolvedValue(updated);
104
+ const result = await service.update(new BadgeId('b-1'), new UpdateBadgeInput({ name: 'New' }));
105
+ expect(result).toEqual(updated);
106
+ expect(mockRepository.update.mock.calls).toEqual([['b-1', { name: 'New' }]]);
107
+ });
108
+ it('should throw BADGE_NOT_FOUND when repository returns null', async () => {
109
+ mockRepository.update.mockResolvedValue(null);
110
+ await expect(service.update(new BadgeId('missing'), new UpdateBadgeInput({}))).rejects.toMatchObject({ code: 'NOT_FOUND' });
111
+ });
112
+ it('should throw DATABASE_ERROR when repository fails', async () => {
113
+ mockRepository.update.mockRejectedValue(new Error('fail'));
114
+ await expect(service.update(new BadgeId('b-1'), new UpdateBadgeInput({}))).rejects.toMatchObject({ code: 'DATABASE_ERROR' });
115
+ });
116
+ });
117
+ describe('delete()', () => {
118
+ it('should delete badge when repository returns true', async () => {
119
+ mockRepository.delete.mockResolvedValue(true);
120
+ await service.delete(new BadgeId('b-1'));
121
+ expect(mockRepository.delete.mock.calls).toEqual([['b-1']]);
122
+ });
123
+ it('should throw BADGE_NOT_FOUND when repository returns false', async () => {
124
+ mockRepository.delete.mockResolvedValue(false);
125
+ await expect(service.delete(new BadgeId('missing'))).rejects.toMatchObject({
126
+ code: 'NOT_FOUND',
127
+ });
128
+ });
129
+ it('should throw DATABASE_ERROR when repository fails', async () => {
130
+ mockRepository.delete.mockRejectedValue(new Error('fail'));
131
+ await expect(service.delete(new BadgeId('b-1'))).rejects.toMatchObject({
132
+ code: 'DATABASE_ERROR',
133
+ });
134
+ });
135
+ });
136
+ });
137
+ //# sourceMappingURL=badge.service.unit.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge.service.unit.spec.js","sourceRoot":"","sources":["../../../src/test/unit/badge.service.unit.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mapper.unit.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapper.unit.spec.d.ts","sourceRoot":"","sources":["../../../src/test/unit/mapper.unit.spec.ts"],"names":[],"mappings":""}