@app-connect/core 1.7.8 → 1.7.10

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.
@@ -0,0 +1,539 @@
1
+ // Use in-memory SQLite for isolated model tests
2
+ jest.mock('../../models/sequelize', () => {
3
+ const { Sequelize } = require('sequelize');
4
+ return {
5
+ sequelize: new Sequelize({
6
+ dialect: 'sqlite',
7
+ storage: ':memory:',
8
+ logging: false,
9
+ }),
10
+ };
11
+ });
12
+
13
+ const { CallLogModel } = require('../../models/callLogModel');
14
+ const { MessageLogModel } = require('../../models/messageLogModel');
15
+ const { UserModel } = require('../../models/userModel');
16
+ const { CacheModel } = require('../../models/cacheModel');
17
+ const { AdminConfigModel } = require('../../models/adminConfigModel');
18
+ const { sequelize } = require('../../models/sequelize');
19
+
20
+ describe('Core Models', () => {
21
+ beforeAll(async () => {
22
+ await CallLogModel.sync({ force: true });
23
+ await MessageLogModel.sync({ force: true });
24
+ await UserModel.sync({ force: true });
25
+ await CacheModel.sync({ force: true });
26
+ await AdminConfigModel.sync({ force: true });
27
+ });
28
+
29
+ afterEach(async () => {
30
+ await CallLogModel.destroy({ where: {} });
31
+ await MessageLogModel.destroy({ where: {} });
32
+ await UserModel.destroy({ where: {} });
33
+ await CacheModel.destroy({ where: {} });
34
+ await AdminConfigModel.destroy({ where: {} });
35
+ });
36
+
37
+ afterAll(async () => {
38
+ await sequelize.close();
39
+ });
40
+
41
+ describe('UserModel', () => {
42
+ test('should create user with required fields', async () => {
43
+ // Arrange & Act
44
+ const user = await UserModel.create({
45
+ id: 'user-1',
46
+ platform: 'testCRM',
47
+ accessToken: 'token-123'
48
+ });
49
+
50
+ // Assert
51
+ expect(user.id).toBe('user-1');
52
+ expect(user.platform).toBe('testCRM');
53
+ expect(user.accessToken).toBe('token-123');
54
+ });
55
+
56
+ test('should create user with all optional fields', async () => {
57
+ // Arrange
58
+ const tokenExpiry = new Date('2024-12-31');
59
+
60
+ // Act
61
+ const user = await UserModel.create({
62
+ id: 'user-full',
63
+ platform: 'testCRM',
64
+ hostname: 'test.example.com',
65
+ accessToken: 'token-123',
66
+ refreshToken: 'refresh-123',
67
+ tokenExpiry: tokenExpiry,
68
+ rcAccountId: 'rc-account-123',
69
+ timezoneOffset: '-08:00',
70
+ timezoneName: 'America/Los_Angeles',
71
+ platformAdditionalInfo: { customField: 'value' },
72
+ userSettings: { autoLog: true }
73
+ });
74
+
75
+ // Assert
76
+ expect(user.hostname).toBe('test.example.com');
77
+ expect(user.refreshToken).toBe('refresh-123');
78
+ expect(user.rcAccountId).toBe('rc-account-123');
79
+ expect(user.platformAdditionalInfo).toEqual({ customField: 'value' });
80
+ expect(user.userSettings).toEqual({ autoLog: true });
81
+ });
82
+
83
+ test('should find user by primary key', async () => {
84
+ // Arrange
85
+ await UserModel.create({
86
+ id: 'user-find',
87
+ platform: 'testCRM',
88
+ accessToken: 'token'
89
+ });
90
+
91
+ // Act
92
+ const user = await UserModel.findByPk('user-find');
93
+
94
+ // Assert
95
+ expect(user).not.toBeNull();
96
+ expect(user.id).toBe('user-find');
97
+ });
98
+
99
+ test('should find user by platform and id', async () => {
100
+ // Arrange
101
+ await UserModel.create({
102
+ id: 'user-platform',
103
+ platform: 'testCRM',
104
+ accessToken: 'token'
105
+ });
106
+
107
+ // Act
108
+ const user = await UserModel.findOne({
109
+ where: { id: 'user-platform', platform: 'testCRM' }
110
+ });
111
+
112
+ // Assert
113
+ expect(user).not.toBeNull();
114
+ expect(user.platform).toBe('testCRM');
115
+ });
116
+
117
+ test('should update user fields', async () => {
118
+ // Arrange
119
+ const user = await UserModel.create({
120
+ id: 'user-update',
121
+ platform: 'testCRM',
122
+ accessToken: 'old-token'
123
+ });
124
+
125
+ // Act
126
+ await user.update({ accessToken: 'new-token' });
127
+
128
+ // Assert
129
+ const updated = await UserModel.findByPk('user-update');
130
+ expect(updated.accessToken).toBe('new-token');
131
+ });
132
+
133
+ test('should delete user', async () => {
134
+ // Arrange
135
+ await UserModel.create({
136
+ id: 'user-delete',
137
+ platform: 'testCRM',
138
+ accessToken: 'token'
139
+ });
140
+
141
+ // Act
142
+ await UserModel.destroy({ where: { id: 'user-delete' } });
143
+
144
+ // Assert
145
+ const user = await UserModel.findByPk('user-delete');
146
+ expect(user).toBeNull();
147
+ });
148
+ });
149
+
150
+ describe('CallLogModel', () => {
151
+ test('should create call log with required fields', async () => {
152
+ // Arrange & Act
153
+ const log = await CallLogModel.create({
154
+ id: 'call-1',
155
+ sessionId: 'session-123',
156
+ platform: 'testCRM',
157
+ thirdPartyLogId: 'third-party-1',
158
+ userId: 'user-1'
159
+ });
160
+
161
+ // Assert
162
+ expect(log.id).toBe('call-1');
163
+ expect(log.sessionId).toBe('session-123');
164
+ expect(log.thirdPartyLogId).toBe('third-party-1');
165
+ });
166
+
167
+ test('should create call log with optional contactId', async () => {
168
+ // Act
169
+ const log = await CallLogModel.create({
170
+ id: 'call-contact',
171
+ sessionId: 'session-456',
172
+ platform: 'testCRM',
173
+ thirdPartyLogId: 'third-party-2',
174
+ userId: 'user-1',
175
+ contactId: 'contact-123'
176
+ });
177
+
178
+ // Assert
179
+ expect(log.contactId).toBe('contact-123');
180
+ });
181
+
182
+ test('should find call logs by session ID', async () => {
183
+ // Arrange
184
+ await CallLogModel.create({
185
+ id: 'call-session',
186
+ sessionId: 'unique-session',
187
+ platform: 'testCRM',
188
+ thirdPartyLogId: 'third-party-3',
189
+ userId: 'user-1'
190
+ });
191
+
192
+ // Act
193
+ const log = await CallLogModel.findOne({
194
+ where: { sessionId: 'unique-session' }
195
+ });
196
+
197
+ // Assert
198
+ expect(log).not.toBeNull();
199
+ expect(log.id).toBe('call-session');
200
+ });
201
+
202
+ test('should find multiple call logs by session IDs', async () => {
203
+ // Arrange
204
+ await CallLogModel.bulkCreate([
205
+ { id: 'call-multi-1', sessionId: 'session-a', platform: 'testCRM', thirdPartyLogId: 'tp-1', userId: 'user-1' },
206
+ { id: 'call-multi-2', sessionId: 'session-b', platform: 'testCRM', thirdPartyLogId: 'tp-2', userId: 'user-1' },
207
+ { id: 'call-multi-3', sessionId: 'session-c', platform: 'testCRM', thirdPartyLogId: 'tp-3', userId: 'user-1' }
208
+ ]);
209
+
210
+ // Act
211
+ const { Op } = require('sequelize');
212
+ const logs = await CallLogModel.findAll({
213
+ where: {
214
+ sessionId: { [Op.in]: ['session-a', 'session-c'] }
215
+ }
216
+ });
217
+
218
+ // Assert
219
+ expect(logs).toHaveLength(2);
220
+ });
221
+ });
222
+
223
+ describe('MessageLogModel', () => {
224
+ test('should create message log with required fields', async () => {
225
+ // Arrange & Act
226
+ const log = await MessageLogModel.create({
227
+ id: 'msg-1',
228
+ platform: 'testCRM',
229
+ conversationId: 'conv-123',
230
+ thirdPartyLogId: 'third-party-msg-1',
231
+ userId: 'user-1'
232
+ });
233
+
234
+ // Assert
235
+ expect(log.id).toBe('msg-1');
236
+ expect(log.conversationId).toBe('conv-123');
237
+ });
238
+
239
+ test('should create message log with conversationLogId', async () => {
240
+ // Act
241
+ const log = await MessageLogModel.create({
242
+ id: 'msg-conv',
243
+ platform: 'testCRM',
244
+ conversationId: 'conv-456',
245
+ conversationLogId: 'conv-log-456',
246
+ thirdPartyLogId: 'third-party-msg-2',
247
+ userId: 'user-1'
248
+ });
249
+
250
+ // Assert
251
+ expect(log.conversationLogId).toBe('conv-log-456');
252
+ });
253
+
254
+ test('should find message logs by conversation ID', async () => {
255
+ // Arrange
256
+ await MessageLogModel.create({
257
+ id: 'msg-find',
258
+ platform: 'testCRM',
259
+ conversationId: 'conv-find',
260
+ thirdPartyLogId: 'third-party-find',
261
+ userId: 'user-1'
262
+ });
263
+
264
+ // Act
265
+ const log = await MessageLogModel.findOne({
266
+ where: { conversationId: 'conv-find' }
267
+ });
268
+
269
+ // Assert
270
+ expect(log).not.toBeNull();
271
+ expect(log.id).toBe('msg-find');
272
+ });
273
+
274
+ test('should find message logs by conversationLogId', async () => {
275
+ // Arrange
276
+ await MessageLogModel.create({
277
+ id: 'msg-conv-log',
278
+ platform: 'testCRM',
279
+ conversationId: 'conv-789',
280
+ conversationLogId: 'conv-log-789',
281
+ thirdPartyLogId: 'third-party-789',
282
+ userId: 'user-1'
283
+ });
284
+
285
+ // Act
286
+ const log = await MessageLogModel.findOne({
287
+ where: { conversationLogId: 'conv-log-789' }
288
+ });
289
+
290
+ // Assert
291
+ expect(log).not.toBeNull();
292
+ expect(log.conversationLogId).toBe('conv-log-789');
293
+ });
294
+ });
295
+
296
+ describe('CacheModel', () => {
297
+ test('should create cache entry', async () => {
298
+ // Arrange & Act
299
+ const cache = await CacheModel.create({
300
+ id: 'cache-1',
301
+ userId: 'user-123',
302
+ cacheKey: 'contacts',
303
+ status: 'active'
304
+ });
305
+
306
+ // Assert
307
+ expect(cache.id).toBe('cache-1');
308
+ expect(cache.userId).toBe('user-123');
309
+ expect(cache.cacheKey).toBe('contacts');
310
+ expect(cache.status).toBe('active');
311
+ });
312
+
313
+ test('should update cache status', async () => {
314
+ // Arrange
315
+ const cache = await CacheModel.create({
316
+ id: 'cache-update',
317
+ userId: 'user-123',
318
+ cacheKey: 'contacts',
319
+ status: 'pending'
320
+ });
321
+
322
+ // Act
323
+ await cache.update({ status: 'completed' });
324
+
325
+ // Assert
326
+ const updated = await CacheModel.findByPk('cache-update');
327
+ expect(updated.status).toBe('completed');
328
+ });
329
+
330
+ test('should find cache by userId and cacheKey', async () => {
331
+ // Arrange
332
+ await CacheModel.create({
333
+ id: 'cache-find',
334
+ userId: 'user-find',
335
+ cacheKey: 'contacts-cache',
336
+ status: 'active'
337
+ });
338
+
339
+ // Act
340
+ const cache = await CacheModel.findOne({
341
+ where: { userId: 'user-find', cacheKey: 'contacts-cache' }
342
+ });
343
+
344
+ // Assert
345
+ expect(cache).not.toBeNull();
346
+ expect(cache.status).toBe('active');
347
+ });
348
+ });
349
+
350
+ describe('AdminConfigModel', () => {
351
+ test('should create admin config with basic settings', async () => {
352
+ // Arrange & Act
353
+ const config = await AdminConfigModel.create({
354
+ id: 'admin-1',
355
+ userSettings: { autoLogCalls: true, autoLogMessages: false }
356
+ });
357
+
358
+ // Assert
359
+ expect(config.id).toBe('admin-1');
360
+ expect(config.userSettings).toEqual({ autoLogCalls: true, autoLogMessages: false });
361
+ });
362
+
363
+ test('should create admin config with tokens', async () => {
364
+ // Arrange
365
+ const expiry = new Date('2024-12-31');
366
+
367
+ // Act
368
+ const config = await AdminConfigModel.create({
369
+ id: 'admin-tokens',
370
+ adminAccessToken: 'access-token',
371
+ adminRefreshToken: 'refresh-token',
372
+ adminTokenExpiry: expiry
373
+ });
374
+
375
+ // Assert
376
+ expect(config.adminAccessToken).toBe('access-token');
377
+ expect(config.adminRefreshToken).toBe('refresh-token');
378
+ });
379
+
380
+ test('should create admin config with user mappings', async () => {
381
+ // Arrange
382
+ const userMappings = [
383
+ { crmUserId: 'crm-1', rcExtensionId: ['ext-1'] },
384
+ { crmUserId: 'crm-2', rcExtensionId: ['ext-2', 'ext-3'] }
385
+ ];
386
+
387
+ // Act
388
+ const config = await AdminConfigModel.create({
389
+ id: 'admin-mappings',
390
+ userMappings: userMappings
391
+ });
392
+
393
+ // Assert
394
+ expect(config.userMappings).toEqual(userMappings);
395
+ });
396
+
397
+ test('should update admin config settings', async () => {
398
+ // Arrange
399
+ const config = await AdminConfigModel.create({
400
+ id: 'admin-update',
401
+ userSettings: { autoLog: false }
402
+ });
403
+
404
+ // Act
405
+ await config.update({ userSettings: { autoLog: true } });
406
+
407
+ // Assert
408
+ const updated = await AdminConfigModel.findByPk('admin-update');
409
+ expect(updated.userSettings).toEqual({ autoLog: true });
410
+ });
411
+
412
+ test('should find admin config by primary key', async () => {
413
+ // Arrange
414
+ await AdminConfigModel.create({
415
+ id: 'admin-find',
416
+ userSettings: { enabled: true }
417
+ });
418
+
419
+ // Act
420
+ const config = await AdminConfigModel.findByPk('admin-find');
421
+
422
+ // Assert
423
+ expect(config).not.toBeNull();
424
+ expect(config.id).toBe('admin-find');
425
+ });
426
+ });
427
+
428
+ describe('Model Relationships and Edge Cases', () => {
429
+ test('should handle null JSON fields', async () => {
430
+ // Act
431
+ const user = await UserModel.create({
432
+ id: 'user-null-json',
433
+ platform: 'testCRM',
434
+ accessToken: 'token',
435
+ platformAdditionalInfo: null,
436
+ userSettings: null
437
+ });
438
+
439
+ // Assert
440
+ expect(user.platformAdditionalInfo).toBeNull();
441
+ expect(user.userSettings).toBeNull();
442
+ });
443
+
444
+ test('should handle empty JSON objects', async () => {
445
+ // Act
446
+ const user = await UserModel.create({
447
+ id: 'user-empty-json',
448
+ platform: 'testCRM',
449
+ accessToken: 'token',
450
+ platformAdditionalInfo: {},
451
+ userSettings: {}
452
+ });
453
+
454
+ // Assert
455
+ expect(user.platformAdditionalInfo).toEqual({});
456
+ expect(user.userSettings).toEqual({});
457
+ });
458
+
459
+ test('should handle complex nested JSON', async () => {
460
+ // Arrange
461
+ const complexData = {
462
+ level1: {
463
+ level2: {
464
+ level3: {
465
+ value: 'deep',
466
+ array: [1, 2, 3]
467
+ }
468
+ },
469
+ items: [
470
+ { id: 1, name: 'Item 1' },
471
+ { id: 2, name: 'Item 2' }
472
+ ]
473
+ }
474
+ };
475
+
476
+ // Act
477
+ const user = await UserModel.create({
478
+ id: 'user-complex-json',
479
+ platform: 'testCRM',
480
+ accessToken: 'token',
481
+ platformAdditionalInfo: complexData
482
+ });
483
+
484
+ // Assert
485
+ expect(user.platformAdditionalInfo).toEqual(complexData);
486
+ expect(user.platformAdditionalInfo.level1.level2.level3.value).toBe('deep');
487
+ });
488
+
489
+ test('should enforce unique primary key constraint', async () => {
490
+ // Arrange
491
+ await UserModel.create({
492
+ id: 'unique-user',
493
+ platform: 'testCRM',
494
+ accessToken: 'token-1'
495
+ });
496
+
497
+ // Act & Assert
498
+ await expect(
499
+ UserModel.create({
500
+ id: 'unique-user',
501
+ platform: 'testCRM',
502
+ accessToken: 'token-2'
503
+ })
504
+ ).rejects.toThrow();
505
+ });
506
+
507
+ test('should handle bulk create', async () => {
508
+ // Arrange
509
+ const users = [
510
+ { id: 'bulk-1', platform: 'testCRM', accessToken: 'token-1' },
511
+ { id: 'bulk-2', platform: 'testCRM', accessToken: 'token-2' },
512
+ { id: 'bulk-3', platform: 'testCRM', accessToken: 'token-3' }
513
+ ];
514
+
515
+ // Act
516
+ await UserModel.bulkCreate(users);
517
+
518
+ // Assert
519
+ const count = await UserModel.count({ where: { platform: 'testCRM' } });
520
+ expect(count).toBe(3);
521
+ });
522
+
523
+ test('should handle bulk destroy', async () => {
524
+ // Arrange
525
+ await UserModel.bulkCreate([
526
+ { id: 'destroy-1', platform: 'destroyTest', accessToken: 'token-1' },
527
+ { id: 'destroy-2', platform: 'destroyTest', accessToken: 'token-2' }
528
+ ]);
529
+
530
+ // Act
531
+ await UserModel.destroy({ where: { platform: 'destroyTest' } });
532
+
533
+ // Assert
534
+ const count = await UserModel.count({ where: { platform: 'destroyTest' } });
535
+ expect(count).toBe(0);
536
+ });
537
+ });
538
+ });
539
+