@tomei/sso 0.65.0 → 0.65.1-test.1

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 (33) hide show
  1. package/.gitlab-ci.yml +234 -13
  2. package/.husky/commit-msg +0 -0
  3. package/.husky/pre-commit +0 -0
  4. package/__tests__/unit/components/api-key/api-key.spec.ts +201 -0
  5. package/__tests__/unit/components/group/group.spec.ts +6 -0
  6. package/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.ts +9 -1
  7. package/__tests__/unit/components/login-user/login.spec.ts +1199 -5
  8. package/__tests__/unit/components/system/system.spec.ts +1 -0
  9. package/__tests__/unit/components/user-password-history/user-password-history.spec.ts +165 -0
  10. package/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.ts +233 -0
  11. package/coverage/cobertura-coverage.xml +6837 -0
  12. package/coverage/test-report.xml +161 -0
  13. package/dist/__tests__/unit/components/api-key/api-key.spec.d.ts +1 -0
  14. package/dist/__tests__/unit/components/api-key/api-key.spec.js +158 -0
  15. package/dist/__tests__/unit/components/api-key/api-key.spec.js.map +1 -0
  16. package/dist/__tests__/unit/components/group/group.spec.js +4 -0
  17. package/dist/__tests__/unit/components/group/group.spec.js.map +1 -1
  18. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js +9 -1
  19. package/dist/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.js.map +1 -1
  20. package/dist/__tests__/unit/components/login-user/login.spec.js +703 -0
  21. package/dist/__tests__/unit/components/login-user/login.spec.js.map +1 -1
  22. package/dist/__tests__/unit/components/system/system.spec.js +1 -0
  23. package/dist/__tests__/unit/components/system/system.spec.js.map +1 -1
  24. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.d.ts +1 -0
  25. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js +138 -0
  26. package/dist/__tests__/unit/components/user-password-history/user-password-history.spec.js.map +1 -0
  27. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.d.ts +1 -0
  28. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js +182 -0
  29. package/dist/__tests__/unit/components/user-reporting-hierarchy/user-reporting-hierarchy.spec.js.map +1 -0
  30. package/dist/tsconfig.tsbuildinfo +1 -1
  31. package/jest.config.js +2 -0
  32. package/migrations/20250805085707-add-bulk-approval-code-to-sso-user.js +29 -0
  33. package/package.json +2 -2
@@ -10,12 +10,1206 @@ import SystemPrivilegeModel from '../../../../src/models/system-privilege.entity
10
10
  import { GroupSystemAccessRepository } from '../../../../src/components/group-system-access/group-system-access.repository';
11
11
  import { GroupRepository } from '../../../../src/components/group/group.repository';
12
12
 
13
- // describe('LoginUser', () => {
14
- // afterAll(() => {
15
- // jest.restoreAllMocks();
16
- // });
13
+ const mockUserData = {
14
+ UserId: 1,
15
+ FullName: 'John Doe',
16
+ Email: 'john.doe@example.com',
17
+ Password: 'password',
18
+ Status: 'Active',
19
+ DefaultPasswordChangedYN: 'N',
20
+ FirstLoginAt: new Date(),
21
+ LastLoginAt: new Date(),
22
+ MFAEnabled: 1,
23
+ MFAConfig: 'config',
24
+ RecoveryEmail: 'john.doe@example.com',
25
+ FailedLoginAttemptCount: 0,
26
+ LastFailedLoginAt: null,
27
+ LastPasswordChangedAt: new Date(),
28
+ NeedToChangePasswordYN: 'N',
29
+ CreatedById: 1,
30
+ CreatedAt: new Date(),
31
+ UpdatedById: 1,
32
+ UpdatedAt: new Date(),
33
+ Staff: {
34
+ FullName: 'John Doe',
35
+ IdNo: '1234567890',
36
+ Mobile: '1234567890',
37
+ },
38
+ };
39
+
40
+ const mockSessionService = {
41
+ setUserSession: jest.fn(),
42
+ retrieveUserSession: jest.fn(),
43
+ refreshDuration: jest.fn(),
44
+ };
45
+
46
+ describe('LoginUser', () => {
47
+ beforeAll(() => {
48
+ // Redis env vars needed for RedisService.init() — actual connection is mocked via jest-initial-setup.ts
49
+ process.env.REDIS_HOST = 'localhost';
50
+ process.env.REDIS_PORT = '6379';
51
+ });
52
+
53
+ afterAll(() => {
54
+ jest.restoreAllMocks();
55
+ });
56
+
57
+ describe('init', () => {
58
+ let sessionService: any;
59
+ let userId: number;
60
+ let dbTransaction: any;
61
+
62
+ beforeEach(() => {
63
+ sessionService = {};
64
+ userId = 1;
65
+ dbTransaction = null;
66
+ });
67
+
68
+ it('should initialize LoginUser with valid userId', async () => {
69
+ const user = {
70
+ UserId: 1,
71
+ FullName: 'John Doe',
72
+ Email: 'john.doe@example.com',
73
+ Password: 'password',
74
+ Status: 'active',
75
+ DefaultPasswordChangedYN: 'yes',
76
+ FirstLoginAt: new Date(),
77
+ LastLoginAt: new Date(),
78
+ MFAEnabled: 1,
79
+ MFAConfig: 'config',
80
+ RecoveryEmail: 'john.doe@example.com',
81
+ FailedLoginAttemptCount: 0,
82
+ LastFailedLoginAt: null,
83
+ LastPasswordChangedAt: new Date(),
84
+ NeedToChangePasswordYN: 'no',
85
+ CreatedById: 1,
86
+ CreatedAt: new Date(),
87
+ UpdatedById: 1,
88
+ UpdatedAt: new Date(),
89
+ Staff: {
90
+ FullName: 'John Doe',
91
+ IdNo: '1234567890',
92
+ Mobile: '1234567890',
93
+ },
94
+ };
95
+
96
+ const findOneMock = jest
97
+ .spyOn(UserRepository.prototype, 'findOne')
98
+ .mockResolvedValueOnce(user as any);
99
+
100
+ const result = await LoginUser.init(
101
+ sessionService,
102
+ userId,
103
+ dbTransaction,
104
+ );
105
+
106
+ expect(findOneMock).toHaveBeenCalledTimes(1);
107
+ expect(findOneMock).toHaveBeenCalledWith({
108
+ where: {
109
+ UserId: userId,
110
+ },
111
+ include: [
112
+ {
113
+ model: expect.anything(),
114
+ },
115
+ ],
116
+ transaction: dbTransaction,
117
+ });
118
+ expect(result).toBeInstanceOf(LoginUser);
119
+ expect(result.UserId).toBe(user.UserId);
120
+ expect(result.FullName).toBe(user.FullName);
121
+ expect(result.Email).toBe(user.Email);
122
+ expect(result.Password).toBe(user.Password);
123
+ expect(result.Status).toBe(user.Status);
124
+ expect(result.DefaultPasswordChangedYN).toBe(
125
+ user.DefaultPasswordChangedYN,
126
+ );
127
+ expect(result.FirstLoginAt).toBe(user.FirstLoginAt);
128
+ expect(result.LastLoginAt).toBe(user.LastLoginAt);
129
+ expect(result.MFAEnabled).toBe(user.MFAEnabled);
130
+ expect(result.MFAConfig).toBe(user.MFAConfig);
131
+ expect(result.RecoveryEmail).toBe(user.RecoveryEmail);
132
+ expect(result.FailedLoginAttemptCount).toBe(user.FailedLoginAttemptCount);
133
+ expect(result.LastFailedLoginAt).toBe(user.LastFailedLoginAt);
134
+ expect(result.LastPasswordChangedAt).toBe(user.LastPasswordChangedAt);
135
+ expect(result.NeedToChangePasswordYN).toBe(user.NeedToChangePasswordYN);
136
+ expect(result.CreatedById).toBe(user.CreatedById);
137
+ expect(result.CreatedAt).toBe(user.CreatedAt);
138
+ expect(result.UpdatedById).toBe(user.UpdatedById);
139
+ expect(result.UpdatedAt).toBe(user.UpdatedAt);
140
+ });
141
+
142
+ it('should throw an error when user is not found', async () => {
143
+ const findOneMock = jest
144
+ .spyOn(UserRepository.prototype, 'findOne')
145
+ .mockResolvedValueOnce(null);
146
+
147
+ await expect(
148
+ LoginUser.init(sessionService, userId, dbTransaction),
149
+ ).rejects.toThrow(Error);
150
+
151
+ expect(findOneMock).toHaveBeenCalledTimes(1);
152
+ expect(findOneMock).toHaveBeenCalledWith({
153
+ where: {
154
+ UserId: userId,
155
+ },
156
+ include: [
157
+ {
158
+ model: expect.anything(),
159
+ },
160
+ ],
161
+ transaction: dbTransaction,
162
+ });
163
+ });
164
+ });
165
+
166
+ // describe('checkSession', () => {
167
+ // it('should throw an error if session expired', async () => {
168
+ // // Arrange
169
+ // const systemCode = 'EZC';
170
+ // const sessionId = 'ckymxuh8t000137t011w89zgk';
171
+ // const userId = '755';
172
+ // const sessionService = await SessionService.init();
173
+ // const loginUser = await LoginUser.init(sessionService);
174
+
175
+ // // Act
176
+ // const checkSessionPromise = loginUser.checkSession(
177
+ // systemCode,
178
+ // sessionId,
179
+ // userId,
180
+ // );
181
+
182
+ // // Assert
183
+ // await expect(checkSessionPromise).rejects.toThrow('Session expired.');
184
+ // });
185
+
186
+ // it('should refresh the session duration if session is valid', async () => {
187
+ // // Arrange
188
+ // const systemCode = 'EZC';
189
+ // const sessionId = 'ckymxuh8t000137t011w89zgk';
190
+ // const userId = '755';
191
+ // const sessionService = await SessionService.init();
192
+ // const loginUser = await LoginUser.init(sessionService);
193
+
194
+ // // Mock the _SessionService.retrieveUserSession method
195
+ // loginUser['_SessionService'].retrieveUserSession = jest
196
+ // .fn()
197
+ // .mockResolvedValue({
198
+ // systemLogins: [
199
+ // {
200
+ // code: systemCode,
201
+ // sessionId: sessionId,
202
+ // privileges: [],
203
+ // },
204
+ // ],
205
+ // });
206
+
207
+ // // Mock the _SessionService.refreshDuration method
208
+ // loginUser['_SessionService'].refreshDuration = jest.fn();
209
+
210
+ // // Act
211
+ // const systemLogin = await loginUser.checkSession(
212
+ // systemCode,
213
+ // sessionId,
214
+ // userId,
215
+ // );
216
+
217
+ // // Assert
218
+ // expect(
219
+ // loginUser['_SessionService'].retrieveUserSession,
220
+ // ).toHaveBeenCalledWith(userId);
221
+ // expect(loginUser['_SessionService'].refreshDuration).toHaveBeenCalledWith(
222
+ // userId,
223
+ // );
224
+ // expect(systemLogin).toEqual({
225
+ // code: systemCode,
226
+ // sessionId: sessionId,
227
+ // privileges: [],
228
+ // });
229
+ // });
230
+ // });
231
+
232
+ describe('shouldReleaseLock', () => {
233
+ const minuteToAutoRelease = 5;
234
+ const autoReleaseYN = 'Y';
235
+
236
+ beforeEach(() => {
237
+ jest
238
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
239
+ .mockImplementation((componentName: string, configKey: string) => {
240
+ if (configKey === 'minuteToAutoRelease') {
241
+ return minuteToAutoRelease as any;
242
+ }
243
+ if (configKey === 'autoReleaseYN') {
244
+ return autoReleaseYN as any;
245
+ }
246
+ });
247
+ });
248
+
249
+ it('should return true if autoReleaseYN is "Y" and time difference is greater than minuteToAutoRelease', async () => {
250
+ // Arrange
251
+ const lastFailedLoginAt = new Date();
252
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 10); // Set last failed login time to 10 minutes ago
253
+ // Act
254
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
255
+
256
+ // Assert
257
+ expect(result).toBe(true);
258
+ });
259
+
260
+ it('should return false if autoReleaseYN is "Y" and time difference is less than or equal to minuteToAutoRelease', async () => {
261
+ // Arrange
262
+ const lastFailedLoginAt = new Date();
263
+ lastFailedLoginAt.setMinutes(lastFailedLoginAt.getMinutes() - 3); // Set last failed login time to 3 minutes ago
264
+
265
+ // Act
266
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
267
+
268
+ // Assert
269
+ expect(result).toBe(false);
270
+ });
271
+
272
+ it('should return false if autoReleaseYN is "N"', async () => {
273
+ // Arrange
274
+ const lastFailedLoginAt = new Date();
275
+
276
+ // Act
277
+ const result = LoginUser.shouldReleaseLock(lastFailedLoginAt);
278
+
279
+ // Assert
280
+ expect(result).toBe(false);
281
+ });
282
+ });
283
+
284
+ describe('releaseLock', () => {
285
+ it('should release the lock for a user', async () => {
286
+ // Mock the necessary dependencies and setup the test data
287
+ const UserId = 1;
288
+ const dbTransaction = null;
289
+
290
+ const updateMock = jest
291
+ .spyOn(LoginUser['_Repository'], 'update')
292
+ .mockImplementationOnce(() => Promise.resolve({}) as any);
293
+
294
+ // Call the method under test
295
+ LoginUser['releaseLock'](UserId, dbTransaction);
296
+
297
+ // Verify the expected behavior
298
+ expect(updateMock).toHaveBeenCalledTimes(1);
299
+ expect(updateMock).toHaveBeenCalledWith(
300
+ {
301
+ FailedLoginAttemptCount: 0,
302
+ Status: 'Active',
303
+ },
304
+ {
305
+ where: {
306
+ UserId,
307
+ },
308
+ transaction: dbTransaction,
309
+ },
310
+ );
311
+ });
312
+ });
313
+
314
+ describe('checkUserInfoDuplicated', () => {
315
+ it('should throw an error if duplicate user info is found', async () => {
316
+ // Mock the dependencies and setup the test data
317
+ const dbTransaction = null;
318
+ const query = {
319
+ Email: 'test@example.com',
320
+ IdType: 'passport',
321
+ IdNo: '123456789',
322
+ ContactNo: '1234567890',
323
+ };
324
+
325
+ // Mock the LoginUser['_Repository'].findAll method to return a user
326
+ jest
327
+ .spyOn(LoginUser['_Repository'], 'findAll')
328
+ .mockResolvedValueOnce([{ id: 1 }] as any);
329
+
330
+ // Assert that the method throws an error
331
+ await expect(
332
+ LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
333
+ ).rejects.toThrow();
334
+ });
335
+
336
+ it('should not throw an error if duplicate user info is not found', async () => {
337
+ // Mock the dependencies and setup the test data
338
+ const dbTransaction = null;
339
+ const query = {
340
+ Email: 'test@example.com',
341
+ IdType: 'passport',
342
+ IdNo: '123456789',
343
+ ContactNo: '1234567890',
344
+ };
345
+
346
+ // Mock the LoginUser['_Repository'].findAll method to return an empty array
347
+ jest.spyOn(LoginUser['_Repository'], 'findAll').mockResolvedValueOnce([]);
348
+
349
+ // Assert that the method does not throw an error
350
+ await expect(
351
+ LoginUser['checkUserInfoDuplicated'](dbTransaction, query),
352
+ ).resolves.not.toThrow();
353
+ });
354
+ });
355
+
356
+ describe('generateDefaultPassword', () => {
357
+ const passwordPolicy = {
358
+ minLen: 6,
359
+ maxLen: 10,
360
+ nonAcceptableChar: 'i,l,o',
361
+ numOfCapitalLetters: 1,
362
+ numOfNumbers: 1,
363
+ numOfSpecialChars: 1,
364
+ };
365
+ beforeEach(() => {
366
+ jest
367
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
368
+ .mockImplementation((componentName: string, configKey: string) => {
369
+ if (configKey === 'passwordPolicy') {
370
+ return passwordPolicy as any;
371
+ }
372
+ });
373
+ });
374
+
375
+ it('should generate a default password with the specified length', () => {
376
+ const password = LoginUser['generateDefaultPassword']();
377
+ expect(password.length).toBeGreaterThanOrEqual(6);
378
+ expect(password.length).toBeLessThanOrEqual(10);
379
+ });
380
+
381
+ it('should generate a default password with at least one capital letter', () => {
382
+ const password = LoginUser['generateDefaultPassword']();
383
+ expect(/[A-Z]/.test(password)).toBe(true);
384
+ });
385
+
386
+ it('should generate a default password with at least one number', () => {
387
+ const password = LoginUser['generateDefaultPassword']();
388
+ expect(/[0-9]/.test(password)).toBe(true);
389
+ });
390
+
391
+ it('should generate a default password with at least one special character', () => {
392
+ const password = LoginUser['generateDefaultPassword']();
393
+ expect(/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~`]/.test(password)).toBe(true);
394
+ });
395
+
396
+ it('should generate a default password without any non-acceptable characters', () => {
397
+ const password = LoginUser['generateDefaultPassword']();
398
+ const nonAcceptableChars = ['i', 'l', 'o'];
399
+ expect(nonAcceptableChars.some((char) => password.includes(char))).toBe(
400
+ false,
401
+ );
402
+ });
403
+ });
404
+
405
+ describe('setPassword', () => {
406
+ const passwordPolicy = {
407
+ minLen: 6,
408
+ maxLen: 10,
409
+ nonAcceptableChar: 'i,l,o',
410
+ numOfCapitalLetters: 1,
411
+ numOfNumbers: 1,
412
+ numOfSpecialChars: 1,
413
+ };
414
+ beforeEach(() => {
415
+ jest
416
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
417
+ .mockImplementation((componentName: string, configKey: string) => {
418
+ if (configKey === 'passwordPolicy') {
419
+ return passwordPolicy as any;
420
+ }
421
+ });
422
+ });
423
+
424
+ it('should set the password for the user', async () => {
425
+ // Arrange
426
+ const dbTransaction = null;
427
+ const sessionService = await SessionService.init();
428
+ const user = await LoginUser.init(sessionService);
429
+ const password = 'N3wP@ssw0';
430
+
431
+ // Act
432
+ const result = await LoginUser['setPassword'](
433
+ dbTransaction,
434
+ user,
435
+ password,
436
+ );
437
+
438
+ // Assert
439
+ expect(result).toBeInstanceOf(LoginUser);
440
+ await expect(
441
+ LoginUser['setPassword'](dbTransaction, user, password),
442
+ ).resolves.not.toThrow();
443
+ expect(result.Password).toBeDefined();
444
+ });
445
+
446
+ it('should throw an error if the password does not meet the security requirements', async () => {
447
+ // Arrange
448
+ const dbTransaction = null;
449
+ const sessionService = await SessionService.init();
450
+ const user = await LoginUser.init(sessionService);
451
+ const password = 'weakpassword';
452
+
453
+ // Act & Assert
454
+ await expect(
455
+ LoginUser['setPassword'](dbTransaction, user, password),
456
+ ).rejects.toThrow();
457
+ });
458
+ });
459
+
460
+ // describe('create', () => {
461
+ // let loginUser: LoginUser;
462
+ // let dbTransaction: any;
463
+ // let user: LoginUser;
464
+ // let newUser: any;
465
+
466
+ // beforeEach(async () => {
467
+ // const sessionService = await SessionService.init();
468
+ // loginUser = await LoginUser.init(sessionService);
469
+ // dbTransaction = null;
470
+ // newUser = {
471
+ // UserId: 1,
472
+ // FullName: 'John Doe',
473
+ // Email: 'john.doe@example.com',
474
+ // Password: 'password',
475
+ // Status: 'Active',
476
+ // DefaultPasswordChangedYN: 'N',
477
+ // FirstLoginAt: null,
478
+ // LastLoginAt: null,
479
+ // MFAEnabled: null,
480
+ // MFAConfig: null,
481
+ // RecoveryEmail: null,
482
+ // FailedLoginAttemptCount: 0,
483
+ // LastFailedLoginAt: null,
484
+ // LastPasswordChangedAt: new Date(),
485
+ // NeedToChangePasswordYN: 'N',
486
+ // CreatedById: 1,
487
+ // CreatedAt: new Date(),
488
+ // UpdatedById: 1,
489
+ // UpdatedAt: new Date(),
490
+ // Staff: {
491
+ // FullName: 'John Doe',
492
+ // IdNo: '1234567890',
493
+ // Mobile: '1234567890',
494
+ // },
495
+ // };
496
+ // user = new (LoginUser as any)(sessionService, null, newUser);
497
+ // });
498
+
499
+ // afterEach(() => {
500
+ // jest.clearAllMocks();
501
+ // });
502
+
503
+ // it('should create a new user record', async () => {
504
+ // const checkPrivilegesMock = jest
505
+ // .spyOn(loginUser, 'checkPrivileges')
506
+ // .mockResolvedValueOnce(true);
507
+
508
+ // const checkUserInfoDuplicatedMock = jest
509
+ // .spyOn(LoginUser as any, 'checkUserInfoDuplicated')
510
+ // .mockResolvedValueOnce(undefined);
511
+
512
+ // const generateDefaultPasswordMock = jest
513
+ // .spyOn(LoginUser as any, 'generateDefaultPassword')
514
+ // .mockReturnValueOnce('defaultPassword');
515
+
516
+ // const setPasswordMock = jest
517
+ // .spyOn(LoginUser as any, 'setPassword')
518
+ // .mockResolvedValueOnce(user);
519
+
520
+ // const createMock = jest
521
+ // .spyOn((LoginUser as any)['_Repository'], 'create')
522
+ // .mockResolvedValueOnce({
523
+ // ...newUser,
524
+ // get: () => newUser,
525
+ // });
526
+
527
+ // const activityCreateMock = jest
528
+ // .spyOn((Activity as any).prototype, 'create')
529
+ // .mockResolvedValueOnce(undefined);
530
+
531
+ // jest
532
+ // .spyOn(ApplicationConfig, 'getComponentConfigValue')
533
+ // .mockImplementation((configKey: string) => {
534
+ // if (configKey === 'system-code') {
535
+ // return 'SC';
536
+ // }
537
+ // });
538
+
539
+ // const result = await LoginUser.create(loginUser, dbTransaction, user);
540
+
541
+ // expect(checkPrivilegesMock).toHaveBeenCalledTimes(1);
542
+ // expect(checkPrivilegesMock).toHaveBeenCalledWith(
543
+ // ApplicationConfig.getComponentConfigValue('system-code'),
544
+ // 'User - Create',
545
+ // );
546
+
547
+ // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledTimes(1);
548
+ // expect(checkUserInfoDuplicatedMock).toHaveBeenCalledWith(dbTransaction, {
549
+ // Email: user.Email,
550
+ // IdType: user.IDType,
551
+ // IdNo: user.IDNo,
552
+ // ContactNo: user.ContactNo,
553
+ // });
554
+
555
+ // expect(generateDefaultPasswordMock).toHaveBeenCalledTimes(1);
556
+
557
+ // expect(setPasswordMock).toHaveBeenCalledTimes(1);
558
+ // expect(setPasswordMock).toHaveBeenCalledWith(
559
+ // dbTransaction,
560
+ // user,
561
+ // 'defaultPassword',
562
+ // );
563
+
564
+ // expect(createMock).toHaveBeenCalledTimes(1);
565
+
566
+ // const userInfo = {
567
+ // FullName: user.FullName,
568
+ // IDNo: user.IDNo,
569
+ // Email: user.Email,
570
+ // ContactNo: user.ContactNo,
571
+ // Password: user.Password,
572
+ // Status: UserStatus.ACTIVE,
573
+ // FirstLoginAt: null,
574
+ // LastLoginAt: null,
575
+ // MFAEnabled: null,
576
+ // MFAConfig: null,
577
+ // RecoveryEmail: null,
578
+ // FailedLoginAttemptCount: 0,
579
+ // LastFailedLoginAt: null,
580
+ // LastPasswordChangedAt: null,
581
+ // DefaultPasswordChangedYN: YN.No,
582
+ // NeedToChangePasswordYN: YN.Yes,
583
+ // CreatedById: loginUser.UserId,
584
+ // CreatedAt: new Date(),
585
+ // UpdatedById: loginUser.UserId,
586
+ // UpdatedAt: new Date(),
587
+ // UserId: null,
588
+ // };
589
+
590
+ // expect(createMock).toHaveBeenCalledWith(
591
+ // {
592
+ // Email: userInfo.Email,
593
+ // Password: userInfo.Password,
594
+ // Status: userInfo.Status,
595
+ // DefaultPasswordChangedYN: userInfo.DefaultPasswordChangedYN,
596
+ // FirstLoginAt: userInfo.FirstLoginAt,
597
+ // LastLoginAt: userInfo.LastLoginAt,
598
+ // MFAEnabled: userInfo.MFAEnabled,
599
+ // MFAConfig: userInfo.MFAConfig,
600
+ // RecoveryEmail: userInfo.RecoveryEmail,
601
+ // FailedLoginAttemptCount: userInfo.FailedLoginAttemptCount,
602
+ // LastFailedLoginAt: userInfo.LastFailedLoginAt,
603
+ // LastPasswordChangedAt: userInfo.LastPasswordChangedAt,
604
+ // NeedToChangePasswordYN: userInfo.NeedToChangePasswordYN,
605
+ // CreatedById: userInfo.CreatedById,
606
+ // CreatedAt: expect.any(Date),
607
+ // UpdatedById: userInfo.UpdatedById,
608
+ // UpdatedAt: expect.any(Date),
609
+ // },
610
+ // {
611
+ // transaction: dbTransaction,
612
+ // },
613
+ // );
614
+
615
+ // expect(activityCreateMock).toHaveBeenCalledTimes(1);
616
+
617
+ // expect(result).toBeInstanceOf(LoginUser);
618
+ // expect(result.Email).toBe(userInfo.Email);
619
+ // expect(result.Password).toBe(userInfo.Password);
620
+ // expect(result.Status).toBe(userInfo.Status);
621
+ // expect(result.DefaultPasswordChangedYN).toBe(
622
+ // userInfo.DefaultPasswordChangedYN,
623
+ // );
624
+ // expect(result.FirstLoginAt).toBe(null);
625
+ // expect(result.LastLoginAt).toBe(null);
626
+ // expect(result.MFAEnabled).toBe(userInfo.MFAEnabled);
627
+ // expect(result.MFAConfig).toBe(userInfo.MFAConfig);
628
+ // expect(result.RecoveryEmail).toBe(userInfo.RecoveryEmail);
629
+ // expect(result.FailedLoginAttemptCount).toBe(
630
+ // userInfo.FailedLoginAttemptCount,
631
+ // );
632
+ // expect(result.LastFailedLoginAt).toBe(userInfo.LastFailedLoginAt);
633
+ // expect(result.LastPasswordChangedAt).toBe(userInfo.LastPasswordChangedAt);
634
+ // expect(result.NeedToChangePasswordYN).toBe(
635
+ // userInfo.NeedToChangePasswordYN,
636
+ // );
637
+ // expect(result.CreatedById).toBe(userInfo.CreatedById);
638
+ // expect(result.UpdatedById).toBe(userInfo.UpdatedById);
639
+ // });
640
+
641
+ // it('should throw an error if user dont have the privilege to create new user', async () => {
642
+ // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(false);
643
+
644
+ // await expect(
645
+ // LoginUser.create(loginUser, dbTransaction, user),
646
+ // ).rejects.toThrow(ClassError);
647
+ // });
648
+
649
+ // it('should throw an error if user email is missing', async () => {
650
+ // user.Email = undefined;
651
+
652
+ // jest.spyOn(loginUser, 'checkPrivileges').mockResolvedValueOnce(true);
653
+
654
+ // await expect(
655
+ // LoginUser.create(loginUser, dbTransaction, user),
656
+ // ).rejects.toThrow(ClassError);
657
+ // });
658
+ // });
659
+
660
+ describe('incrementFailedLoginAttemptCount', () => {
661
+ afterAll(() => {
662
+ jest.restoreAllMocks();
663
+ });
664
+
665
+ it('should increment FailedLoginAttemptCount and update user status', async () => {
666
+ // Arrange
667
+ const sessionService = await SessionService.init();
668
+ const loginUser = await LoginUser.init(sessionService);
669
+ loginUser['FailedLoginAttemptCount'] = 2;
670
+ loginUser['LastFailedLoginAt'] = new Date();
671
+ loginUser['Status'] = UserStatus.ACTIVE;
672
+
673
+ const dbTransaction = null;
674
+
675
+ // Mock the static methods and properties
676
+ jest
677
+ .spyOn((LoginUser as any)['_Repository'], 'update')
678
+ .mockReturnValueOnce(null);
679
+
680
+ jest
681
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
682
+ .mockImplementation((componentName: string, configKey: string) => {
683
+ if (configKey === 'maxFailedLoginAttempts') {
684
+ return 3;
685
+ }
686
+ if (configKey === 'autoReleaseYN') {
687
+ return 'Y';
688
+ }
689
+ });
690
+
691
+ // Act
692
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
693
+
694
+ // Assert
695
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
696
+ {
697
+ FailedLoginAttemptCount: 3,
698
+ LastFailedLoginAt: expect.any(Date),
699
+ Status: UserStatus.ACTIVE,
700
+ },
701
+ {
702
+ where: {
703
+ UserId: loginUser.UserId,
704
+ },
705
+ transaction: dbTransaction,
706
+ },
707
+ );
708
+ });
709
+
710
+ it('should throw an error if maxFailedLoginAttempts or autoReleaseYN is missing', async () => {
711
+ // Arrange
712
+ const sessionService = await SessionService.init();
713
+ const loginUser = await LoginUser.init(sessionService);
714
+ loginUser['FailedLoginAttemptCount'] = 2;
715
+ loginUser['LastFailedLoginAt'] = new Date();
716
+ loginUser['Status'] = UserStatus.ACTIVE;
717
+
718
+ const dbTransaction = null;
719
+
720
+ // Mock the static methods and properties
721
+ jest
722
+ .spyOn((LoginUser as any)['_Repository'], 'update')
723
+ .mockReturnValueOnce(null);
724
+
725
+ jest
726
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
727
+ .mockImplementationOnce((componentName: string, configKey: string) => {
728
+ if (configKey === 'maxFailedLoginAttempts') {
729
+ return undefined;
730
+ }
731
+ if (configKey === 'autoReleaseYN') {
732
+ return undefined;
733
+ }
734
+ });
735
+
736
+ // Act and Assert
737
+ await expect(
738
+ loginUser['incrementFailedLoginAttemptCount'](dbTransaction),
739
+ ).rejects.toThrow(
740
+ new ClassError(
741
+ 'LoginUser',
742
+ 'LoginUserErrMsg0X',
743
+ 'Missing maxFailedLoginAttempts and or autoReleaseYN. Please set in config file.',
744
+ ),
745
+ );
746
+ });
747
+
748
+ it('should lock the user account if the failed login attempts exceed the maximum allowed', async () => {
749
+ // Arrange
750
+ const sessionService = await SessionService.init();
751
+ const loginUser = await LoginUser.init(sessionService);
752
+ loginUser['FailedLoginAttemptCount'] = 3;
753
+ loginUser['LastFailedLoginAt'] = new Date();
754
+ loginUser['Status'] = UserStatus.ACTIVE;
755
+
756
+ const dbTransaction = null;
757
+
758
+ // Mock the static methods and properties
759
+ jest
760
+ .spyOn((LoginUser as any)['_Repository'], 'update')
761
+ .mockReturnValueOnce(null);
762
+
763
+ jest
764
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
765
+ .mockImplementation((componentName: string, configKey: string) => {
766
+ if (configKey === 'maxFailedLoginAttempts') {
767
+ return 3;
768
+ }
769
+ if (configKey === 'autoReleaseYN') {
770
+ return 'Y';
771
+ }
772
+ });
773
+
774
+ // Act
775
+ try {
776
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
777
+ expect(false).toBe(true);
778
+ } catch (error) {
779
+ // Assert
780
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
781
+ {
782
+ FailedLoginAttemptCount: 4,
783
+ LastFailedLoginAt: expect.any(Date),
784
+ Status: UserStatus.LOCKED,
785
+ },
786
+ {
787
+ where: {
788
+ UserId: loginUser.UserId,
789
+ },
790
+ transaction: dbTransaction,
791
+ },
792
+ );
793
+ expect(error).toBeInstanceOf(ClassError);
794
+ expect(error.message).toBe(
795
+ 'Your account has been temporarily locked due to too many failed login attempts, please try again later.',
796
+ );
797
+ }
798
+ });
799
+
800
+ it('should permanently lock the user account if the failed login attempts exceed the maximum allowed and autoReleaseYN is N', async () => {
801
+ // Arrange
802
+ const sessionService = await SessionService.init();
803
+ const loginUser = await LoginUser.init(sessionService);
804
+ loginUser['FailedLoginAttemptCount'] = 3;
805
+ loginUser['LastFailedLoginAt'] = new Date();
806
+ loginUser['Status'] = UserStatus.ACTIVE;
807
+
808
+ const dbTransaction = null;
809
+
810
+ // Mock the static methods and properties
811
+ jest
812
+ .spyOn((LoginUser as any)['_Repository'], 'update')
813
+ .mockReturnValueOnce(null);
814
+
815
+ jest
816
+ .spyOn(ComponentConfig, 'getComponentConfigValue')
817
+ .mockImplementation((componentName: string, configKey: string) => {
818
+ if (configKey === 'maxFailedLoginAttempts') {
819
+ return 3;
820
+ }
821
+ if (configKey === 'autoReleaseYN') {
822
+ return 'N';
823
+ }
824
+ });
825
+
826
+ // Act
827
+ try {
828
+ await loginUser['incrementFailedLoginAttemptCount'](dbTransaction);
829
+ expect(false).toBe(true);
830
+ } catch (error) {
831
+ // Assert
832
+ expect(LoginUser['_Repository'].update).toHaveBeenCalledWith(
833
+ {
834
+ FailedLoginAttemptCount: 4,
835
+ LastFailedLoginAt: expect.any(Date),
836
+ Status: UserStatus.LOCKED,
837
+ },
838
+ {
839
+ where: {
840
+ UserId: loginUser.UserId,
841
+ },
842
+ transaction: dbTransaction,
843
+ },
844
+ );
845
+ expect(error).toBeInstanceOf(ClassError);
846
+ expect(error.message).toBe(
847
+ 'Your account has been locked due to too many failed login attempts, please contact IT Support for instructions on how to unlock your account',
848
+ );
849
+ }
850
+ });
851
+ });
852
+
853
+ describe('combineSystemAccess', () => {
854
+ it('should combine user and group system access and remove duplicates', async () => {
855
+ // Mock the necessary dependencies
856
+ const sessionService = await SessionService.init();
857
+ const loginUser = await LoginUser.init(sessionService);
858
+ const dbTransaction = null;
859
+ const groups = [
860
+ { InheritParentSystemAccessYN: true },
861
+ { InheritParentSystemAccessYN: false },
862
+ ];
863
+
864
+ // Mock the necessary repository methods
865
+ jest
866
+ .spyOn(LoginUser as any, 'getInheritedSystemAccess')
867
+ .mockResolvedValueOnce([
868
+ { SystemCode: 'system1' },
869
+ { SystemCode: 'system2' },
870
+ ]);
871
+ jest
872
+ .spyOn((LoginUser as any)['_UserSystemAccessRepo'], 'findAll')
873
+ .mockResolvedValueOnce([{ SystemCode: 'system3' }]);
874
+
875
+ // Call the method
876
+ const result = await LoginUser['combineSystemAccess'](
877
+ loginUser,
878
+ dbTransaction,
879
+ groups,
880
+ );
881
+
882
+ // Assert the result
883
+ expect(result).toEqual([
884
+ { SystemCode: 'system3' },
885
+ { SystemCode: 'system1' },
886
+ { SystemCode: 'system2' },
887
+ ]);
888
+ });
889
+ });
890
+
891
+ describe('checkPrivileges', () => {
892
+ beforeEach(() => {
893
+ jest
894
+ .spyOn(ApplicationConfig, 'getComponentConfigValue')
895
+ .mockReturnValue('test-session' as any);
896
+ });
897
+
898
+ it('should return true if user has the specified privilege', async () => {
899
+ // Arrange
900
+ const systemCode = 'SS';
901
+ const privilegeName = 'Privilege 1';
902
+ const sessionService = await SessionService.init();
903
+ const loginUser = await LoginUser.init(sessionService);
904
+ loginUser.ObjectId = '1';
905
+
906
+ // Mock the necessary methods
907
+ const rus = jest
908
+ .spyOn(SessionService.prototype, 'retrieveUserSession')
909
+ .mockResolvedValueOnce({
910
+ systemLogins: [
911
+ {
912
+ id: '1',
913
+ sessionId: 'sessionId',
914
+ code: systemCode,
915
+ privileges: [privilegeName],
916
+ },
917
+ ],
918
+ });
919
+ // Act
920
+ const hasPrivilege = await loginUser.checkPrivileges(
921
+ systemCode,
922
+ privilegeName,
923
+ );
924
+
925
+ // Assert
926
+ expect(hasPrivilege).toBe(true);
927
+ expect(rus).toHaveBeenCalledWith(loginUser.ObjectId, 'test-session');
928
+ });
929
+
930
+ it('should return false if user does not have the specified privilege', async () => {
931
+ // Arrange
932
+ const systemCode = 'SS';
933
+ const privilegeName = 'Privilege 1';
934
+ const sessionService = await SessionService.init();
935
+ const loginUser = await LoginUser.init(sessionService);
936
+ loginUser.ObjectId = '1';
937
+
938
+ // Mock the necessary methods
939
+ const rus = jest
940
+ .spyOn(SessionService.prototype, 'retrieveUserSession')
941
+ .mockResolvedValueOnce({
942
+ systemLogins: [
943
+ {
944
+ id: '1',
945
+ sessionId: 'sessionId',
946
+ code: systemCode,
947
+ privileges: [],
948
+ },
949
+ ],
950
+ });
951
+ // Act
952
+ const hasPrivilege = await loginUser.checkPrivileges(
953
+ systemCode,
954
+ privilegeName,
955
+ );
956
+
957
+ // Assert
958
+ expect(hasPrivilege).toBe(false);
959
+ expect(rus).toHaveBeenCalledWith(loginUser.ObjectId, 'test-session');
960
+ });
961
+
962
+ it('should throw an error if ObjectId is not set', async () => {
963
+ // Arrange
964
+ const systemCode = 'SS';
965
+ const privilegeName = 'Privilege 1';
966
+ const sessionService = await SessionService.init();
967
+ const loginUser = await LoginUser.init(sessionService);
968
+ loginUser.ObjectId = null;
969
+
970
+ // Act & Assert
971
+ await expect(
972
+ loginUser.checkPrivileges(systemCode, privilegeName),
973
+ ).rejects.toThrow();
974
+ });
975
+ });
976
+
977
+ describe('getObjectPrivileges', () => {
978
+ it('should return an array of privileges', async () => {
979
+ // Mock the dependencies and setup the test data
980
+ const systemCode = 'system1';
981
+ const dbTransaction = null;
982
+ const sessionService = await SessionService.init();
983
+ const loginUser = await LoginUser.init(sessionService);
984
+
985
+ // Mock the UserObjectPrivilegeRepo findAll method
986
+ const findAllMock = jest
987
+ .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
988
+ .mockResolvedValue([
989
+ {
990
+ PrivilegeCode: 'privilege1',
991
+ Privilege: {
992
+ PrivilegeCode: 'privilege1',
993
+ SystemCode: systemCode,
994
+ Name: 'privilege1',
995
+ },
996
+ },
997
+ {
998
+ PrivilegeCode: 'privilege2',
999
+ Privilege: {
1000
+ PrivilegeCode: 'privilege2',
1001
+ Name: 'privilege2',
1002
+ },
1003
+ },
1004
+ ] as any);
1005
+
1006
+ // Call the getObjectPrivileges method
1007
+ const result = await loginUser['getObjectPrivileges'](
1008
+ systemCode,
1009
+ dbTransaction,
1010
+ );
1011
+
1012
+ // Assertions
1013
+ expect(findAllMock).toHaveBeenCalledTimes(1);
1014
+ expect(findAllMock).toHaveBeenCalledWith({
1015
+ where: {
1016
+ UserId: loginUser.UserId,
1017
+ },
1018
+ include: {
1019
+ model: SystemPrivilegeModel,
1020
+ where: {
1021
+ SystemCode: systemCode,
1022
+ Status: 'Active',
1023
+ },
1024
+ },
1025
+ transaction: dbTransaction,
1026
+ });
1027
+ expect(result).toEqual(['privilege1', 'privilege2']);
1028
+ });
1029
+
1030
+ it('should throw an error if an exception occurs', async () => {
1031
+ // Mock the dependencies and setup the test data
1032
+ const systemCode = 'system1';
1033
+ const dbTransaction = null;
1034
+ const sessionService = await SessionService.init();
1035
+ const loginUser = await LoginUser.init(sessionService);
1036
+
1037
+ // Mock the UserObjectPrivilegeRepo findAll method to throw an error
1038
+ jest
1039
+ .spyOn(LoginUser['_UserObjectPrivilegeRepo'], 'findAll')
1040
+ .mockRejectedValue(new Error('Database error'));
1041
+
1042
+ // Call the getObjectPrivileges method and expect it to throw an error
1043
+ await expect(
1044
+ loginUser['getObjectPrivileges'](systemCode, dbTransaction),
1045
+ ).rejects.toThrow(Error);
1046
+ });
1047
+ });
1048
+
1049
+ describe('getUserPersonalPrivileges', () => {
1050
+ it('should return an array of privileges', async () => {
1051
+ // Arrange
1052
+ const sessionService = await SessionService.init();
1053
+ const loginUser = await LoginUser.init(sessionService);
1054
+ const systemCode = 'system1';
1055
+ const dbTransaction = null;
1056
+
1057
+ // Mock the findAll method of UserPrivilegeRepo
1058
+ const findAllMock = jest.spyOn(
1059
+ LoginUser['_UserPrivilegeRepo'],
1060
+ 'findAll',
1061
+ );
1062
+ findAllMock.mockResolvedValue([
1063
+ { Privilege: { PrivilegeCode: 'privilege1' } },
1064
+ { Privilege: { PrivilegeCode: 'privilege2' } },
1065
+ ] as any);
1066
+
1067
+ // Act
1068
+ const privileges = await loginUser['getUserPersonalPrivileges'](
1069
+ systemCode,
1070
+ dbTransaction,
1071
+ );
1072
+
1073
+ // Assert
1074
+ expect(privileges).toEqual(['privilege1', 'privilege2']);
1075
+ expect(findAllMock).toHaveBeenCalledTimes(1);
1076
+ expect(findAllMock).toHaveBeenCalledWith({
1077
+ where: {
1078
+ UserId: loginUser.UserId,
1079
+ Status: 'Active',
1080
+ },
1081
+ include: {
1082
+ model: SystemPrivilegeModel,
1083
+ where: {
1084
+ SystemCode: systemCode,
1085
+ Status: 'Active',
1086
+ },
1087
+ },
1088
+ transaction: dbTransaction,
1089
+ });
1090
+ });
1091
+
1092
+ it('should throw an error if an error occurs', async () => {
1093
+ // Arrange
1094
+ const sessionService = await SessionService.init();
1095
+ const loginUser = await LoginUser.init(sessionService);
1096
+ const systemCode = 'system1';
1097
+ const dbTransaction = null;
1098
+
1099
+ // Mock the findAll method of UserPrivilegeRepo to throw an error
1100
+ const findAllMock = jest.spyOn(
1101
+ LoginUser['_UserPrivilegeRepo'],
1102
+ 'findAll',
1103
+ );
1104
+ findAllMock.mockRejectedValue(new Error('Database error'));
1105
+
1106
+ // Act and Assert
1107
+ await expect(
1108
+ loginUser['getUserPersonalPrivileges'](systemCode, dbTransaction),
1109
+ ).rejects.toThrow(Error);
1110
+
1111
+ expect(findAllMock).toHaveBeenCalledTimes(1);
1112
+ expect(findAllMock).toHaveBeenCalledWith({
1113
+ where: {
1114
+ UserId: loginUser.UserId,
1115
+ Status: 'Active',
1116
+ },
1117
+ include: {
1118
+ model: SystemPrivilegeModel,
1119
+ where: {
1120
+ SystemCode: systemCode,
1121
+ Status: 'Active',
1122
+ },
1123
+ },
1124
+ transaction: dbTransaction,
1125
+ });
1126
+ });
1127
+ });
1128
+
1129
+ describe('getInheritedSystemAccess', () => {
1130
+ it('should return group system access with its parent group system access if applicable', async () => {
1131
+ // Mock the necessary dependencies
1132
+ const dbTransaction = null;
1133
+ const group = {
1134
+ GroupCode: 'group1',
1135
+ InheritParentSystemAccessYN: 'Y',
1136
+ ParentGroupCode: 'parentGroup',
1137
+ } as any;
1138
+ const parentGroup = {
1139
+ GroupCode: 'parentGroup',
1140
+ InheritParentSystemAccessYN: 'N',
1141
+ ParentGroupCode: null,
1142
+ } as any;
1143
+
1144
+ const systemAccess = [
1145
+ {
1146
+ SystemCode: 'system1',
1147
+ GroupCode: 'group1',
1148
+ System: { SystemCode: 'system1' },
1149
+ },
1150
+ {
1151
+ SystemCode: 'system2',
1152
+ GroupCode: 'group1',
1153
+ System: { SystemCode: 'system1' },
1154
+ },
1155
+ ] as any;
1156
+
1157
+ const parentSystemAccess = [
1158
+ {
1159
+ SystemCode: 'system3',
1160
+ GroupCode: 'parentGroup',
1161
+ System: { SystemCode: 'system3' },
1162
+ },
1163
+ ] as any;
1164
+
1165
+ // Mock the necessary repository methods
1166
+ const groupFindByPkMock = jest
1167
+ .spyOn(GroupRepository.prototype, 'findByPk')
1168
+ .mockResolvedValueOnce(parentGroup as any);
1169
+ const systemAccessFindAllMock = jest
1170
+ .spyOn(GroupSystemAccessRepository.prototype, 'findAll')
1171
+ .mockImplementation((options: any) => {
1172
+ if (options.where.GroupCode === group.GroupCode) {
1173
+ return Promise.resolve(systemAccess);
1174
+ } else if (options.where.GroupCode === parentGroup.GroupCode) {
1175
+ return Promise.resolve(parentSystemAccess);
1176
+ }
1177
+ });
1178
+
1179
+ // Call the method
1180
+ const result = await LoginUser['getInheritedSystemAccess'](
1181
+ dbTransaction,
1182
+ group,
1183
+ );
1184
+
1185
+ console.log(result);
1186
+ // Assert the result
1187
+ expect(result).toEqual([
1188
+ {
1189
+ SystemCode: 'system1',
1190
+ GroupCode: 'group1',
1191
+ System: { SystemCode: 'system1' },
1192
+ },
1193
+ {
1194
+ SystemCode: 'system2',
1195
+ GroupCode: 'group1',
1196
+ System: { SystemCode: 'system1' },
1197
+ },
1198
+ {
1199
+ SystemCode: 'system3',
1200
+ GroupCode: 'parentGroup',
1201
+ System: { SystemCode: 'system3' },
1202
+ },
1203
+ ]);
1204
+ expect(groupFindByPkMock).toHaveBeenCalledWith(
1205
+ group.ParentGroupCode,
1206
+ dbTransaction,
1207
+ );
1208
+ expect(systemAccessFindAllMock).toHaveBeenCalledTimes(2);
1209
+ });
1210
+ });
1211
+ });
17
1212
 
18
- // describe('init', () => {
19
1213
  // let sessionService: any;
20
1214
  // let userId: number;
21
1215
  // let dbTransaction: any;