@app-connect/core 0.0.3 → 1.6.4

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.
@@ -1,161 +1,161 @@
1
- const jwt = require('../../lib/jwt');
2
-
3
- describe('JWT Utility', () => {
4
- beforeEach(() => {
5
- // Reset environment
6
- process.env.APP_SERVER_SECRET_KEY = 'test-secret-key';
7
- });
8
-
9
- describe('generateJwt', () => {
10
- test('should generate JWT token from payload', () => {
11
- // Arrange
12
- const payload = {
13
- id: 'test-user-id',
14
- platform: 'testCRM'
15
- };
16
-
17
- // Act
18
- const token = jwt.generateJwt(payload);
19
-
20
- // Assert
21
- expect(token).toBeDefined();
22
- expect(typeof token).toBe('string');
23
- expect(token.split('.')).toHaveLength(3); // JWT has 3 parts
24
- });
25
-
26
- test('should generate different tokens for different payloads', () => {
27
- // Arrange
28
- const payload1 = { id: 'user1', platform: 'testCRM' };
29
- const payload2 = { id: 'user2', platform: 'testCRM' };
30
-
31
- // Act
32
- const token1 = jwt.generateJwt(payload1);
33
- const token2 = jwt.generateJwt(payload2);
34
-
35
- // Assert
36
- expect(token1).not.toBe(token2);
37
- });
38
- });
39
-
40
- describe('decodeJwt', () => {
41
- test('should decode valid JWT token', () => {
42
- // Arrange
43
- const payload = {
44
- id: 'test-user-id',
45
- platform: 'testCRM'
46
- };
47
- const token = jwt.generateJwt(payload);
48
-
49
- // Act
50
- const decoded = jwt.decodeJwt(token);
51
-
52
- // Assert
53
- expect(decoded).toMatchObject(payload);
54
- expect(decoded).toHaveProperty('exp');
55
- expect(decoded).toHaveProperty('iat');
56
- });
57
-
58
- test('should return null for invalid token', () => {
59
- // Arrange
60
- const invalidToken = 'invalid.jwt.token';
61
-
62
- // Act
63
- const decoded = jwt.decodeJwt(invalidToken);
64
-
65
- // Assert
66
- expect(decoded).toBeNull();
67
- });
68
-
69
- test('should return null for malformed token', () => {
70
- // Arrange
71
- const malformedToken = 'not-a-jwt-token';
72
-
73
- // Act
74
- const decoded = jwt.decodeJwt(malformedToken);
75
-
76
- // Assert
77
- expect(decoded).toBeNull();
78
- });
79
-
80
- test('should return null for token with wrong secret', () => {
81
- // Arrange
82
- const payload = { id: 'test-user-id', platform: 'testCRM' };
83
- const token = jwt.generateJwt(payload);
84
-
85
- // Change secret temporarily
86
- const originalSecret = process.env.APP_SERVER_SECRET_KEY;
87
- process.env.APP_SERVER_SECRET_KEY = 'different-secret';
88
-
89
- // Act
90
- const decoded = jwt.decodeJwt(token);
91
-
92
- // Restore secret
93
- process.env.APP_SERVER_SECRET_KEY = originalSecret;
94
-
95
- // Assert
96
- expect(decoded).toBeNull();
97
- });
98
- });
99
-
100
- describe('generateJwt and decodeJwt round trip', () => {
101
- test('should successfully generate and decode complex payload', () => {
102
- // Arrange
103
- const complexPayload = {
104
- id: 'test-user-id',
105
- platform: 'testCRM',
106
- timestamp: Date.now(),
107
- metadata: {
108
- timezone: 'America/Los_Angeles',
109
- preferences: {
110
- autoLog: true,
111
- callPop: false
112
- }
113
- }
114
- };
115
-
116
- // Act
117
- const token = jwt.generateJwt(complexPayload);
118
- const decoded = jwt.decodeJwt(token);
119
-
120
- // Assert
121
- expect(decoded).toMatchObject(complexPayload);
122
- expect(decoded).toHaveProperty('exp');
123
- expect(decoded).toHaveProperty('iat');
124
- });
125
-
126
- test('should handle empty payload', () => {
127
- // Arrange
128
- const emptyPayload = {};
129
-
130
- // Act
131
- const token = jwt.generateJwt(emptyPayload);
132
- const decoded = jwt.decodeJwt(token);
133
-
134
- // Assert
135
- expect(decoded).toMatchObject(emptyPayload);
136
- expect(decoded).toHaveProperty('exp');
137
- expect(decoded).toHaveProperty('iat');
138
- });
139
- });
140
-
141
- describe('error handling', () => {
142
- test('should handle missing secret key', () => {
143
- // Arrange
144
- const payload = { id: 'test-user-id' };
145
- delete process.env.APP_SERVER_SECRET_KEY;
146
-
147
- // Act & Assert
148
- expect(() => jwt.generateJwt(payload)).toThrow();
149
- });
150
-
151
- test('should handle null payload', () => {
152
- // Act & Assert
153
- expect(() => jwt.generateJwt(null)).toThrow();
154
- });
155
-
156
- test('should handle undefined payload', () => {
157
- // Act & Assert
158
- expect(() => jwt.generateJwt(undefined)).toThrow();
159
- });
160
- });
161
- });
1
+ const jwt = require('../../lib/jwt');
2
+
3
+ describe('JWT Utility', () => {
4
+ beforeEach(() => {
5
+ // Reset environment
6
+ process.env.APP_SERVER_SECRET_KEY = 'test-secret-key';
7
+ });
8
+
9
+ describe('generateJwt', () => {
10
+ test('should generate JWT token from payload', () => {
11
+ // Arrange
12
+ const payload = {
13
+ id: 'test-user-id',
14
+ platform: 'testCRM'
15
+ };
16
+
17
+ // Act
18
+ const token = jwt.generateJwt(payload);
19
+
20
+ // Assert
21
+ expect(token).toBeDefined();
22
+ expect(typeof token).toBe('string');
23
+ expect(token.split('.')).toHaveLength(3); // JWT has 3 parts
24
+ });
25
+
26
+ test('should generate different tokens for different payloads', () => {
27
+ // Arrange
28
+ const payload1 = { id: 'user1', platform: 'testCRM' };
29
+ const payload2 = { id: 'user2', platform: 'testCRM' };
30
+
31
+ // Act
32
+ const token1 = jwt.generateJwt(payload1);
33
+ const token2 = jwt.generateJwt(payload2);
34
+
35
+ // Assert
36
+ expect(token1).not.toBe(token2);
37
+ });
38
+ });
39
+
40
+ describe('decodeJwt', () => {
41
+ test('should decode valid JWT token', () => {
42
+ // Arrange
43
+ const payload = {
44
+ id: 'test-user-id',
45
+ platform: 'testCRM'
46
+ };
47
+ const token = jwt.generateJwt(payload);
48
+
49
+ // Act
50
+ const decoded = jwt.decodeJwt(token);
51
+
52
+ // Assert
53
+ expect(decoded).toMatchObject(payload);
54
+ expect(decoded).toHaveProperty('exp');
55
+ expect(decoded).toHaveProperty('iat');
56
+ });
57
+
58
+ test('should return null for invalid token', () => {
59
+ // Arrange
60
+ const invalidToken = 'invalid.jwt.token';
61
+
62
+ // Act
63
+ const decoded = jwt.decodeJwt(invalidToken);
64
+
65
+ // Assert
66
+ expect(decoded).toBeNull();
67
+ });
68
+
69
+ test('should return null for malformed token', () => {
70
+ // Arrange
71
+ const malformedToken = 'not-a-jwt-token';
72
+
73
+ // Act
74
+ const decoded = jwt.decodeJwt(malformedToken);
75
+
76
+ // Assert
77
+ expect(decoded).toBeNull();
78
+ });
79
+
80
+ test('should return null for token with wrong secret', () => {
81
+ // Arrange
82
+ const payload = { id: 'test-user-id', platform: 'testCRM' };
83
+ const token = jwt.generateJwt(payload);
84
+
85
+ // Change secret temporarily
86
+ const originalSecret = process.env.APP_SERVER_SECRET_KEY;
87
+ process.env.APP_SERVER_SECRET_KEY = 'different-secret';
88
+
89
+ // Act
90
+ const decoded = jwt.decodeJwt(token);
91
+
92
+ // Restore secret
93
+ process.env.APP_SERVER_SECRET_KEY = originalSecret;
94
+
95
+ // Assert
96
+ expect(decoded).toBeNull();
97
+ });
98
+ });
99
+
100
+ describe('generateJwt and decodeJwt round trip', () => {
101
+ test('should successfully generate and decode complex payload', () => {
102
+ // Arrange
103
+ const complexPayload = {
104
+ id: 'test-user-id',
105
+ platform: 'testCRM',
106
+ timestamp: Date.now(),
107
+ metadata: {
108
+ timezone: 'America/Los_Angeles',
109
+ preferences: {
110
+ autoLog: true,
111
+ callPop: false
112
+ }
113
+ }
114
+ };
115
+
116
+ // Act
117
+ const token = jwt.generateJwt(complexPayload);
118
+ const decoded = jwt.decodeJwt(token);
119
+
120
+ // Assert
121
+ expect(decoded).toMatchObject(complexPayload);
122
+ expect(decoded).toHaveProperty('exp');
123
+ expect(decoded).toHaveProperty('iat');
124
+ });
125
+
126
+ test('should handle empty payload', () => {
127
+ // Arrange
128
+ const emptyPayload = {};
129
+
130
+ // Act
131
+ const token = jwt.generateJwt(emptyPayload);
132
+ const decoded = jwt.decodeJwt(token);
133
+
134
+ // Assert
135
+ expect(decoded).toMatchObject(emptyPayload);
136
+ expect(decoded).toHaveProperty('exp');
137
+ expect(decoded).toHaveProperty('iat');
138
+ });
139
+ });
140
+
141
+ describe('error handling', () => {
142
+ test('should handle missing secret key', () => {
143
+ // Arrange
144
+ const payload = { id: 'test-user-id' };
145
+ delete process.env.APP_SERVER_SECRET_KEY;
146
+
147
+ // Act & Assert
148
+ expect(() => jwt.generateJwt(payload)).toThrow();
149
+ });
150
+
151
+ test('should handle null payload', () => {
152
+ // Act & Assert
153
+ expect(() => jwt.generateJwt(null)).toThrow();
154
+ });
155
+
156
+ test('should handle undefined payload', () => {
157
+ // Act & Assert
158
+ expect(() => jwt.generateJwt(undefined)).toThrow();
159
+ });
160
+ });
161
+ });
package/test/setup.js CHANGED
@@ -1,176 +1,176 @@
1
- // Test setup for @app-connect/core package
2
- const path = require('path');
3
- require('dotenv').config({ path: path.resolve(__dirname, '../.env.test') });
4
-
5
- // Set test timeout
6
- jest.setTimeout(30000);
7
-
8
- // Mock console methods to reduce noise in tests
9
- global.console = {
10
- ...console,
11
- log: jest.fn(),
12
- debug: jest.fn(),
13
- info: jest.fn(),
14
- warn: jest.fn(),
15
- error: jest.fn(),
16
- };
17
-
18
- // Setup database models for testing
19
- beforeAll(async () => {
20
- try {
21
- // Set up test database URL if not provided
22
- if (!process.env.DATABASE_URL) {
23
- process.env.DATABASE_URL = 'sqlite::memory:';
24
- }
25
-
26
- // Import models
27
- const { CallLogModel } = require('../models/callLogModel');
28
- const { MessageLogModel } = require('../models/messageLogModel');
29
- const { UserModel } = require('../models/userModel');
30
- const { CacheModel } = require('../models/cacheModel');
31
- const { AdminConfigModel } = require('../models/adminConfigModel');
32
-
33
- // Sync database models
34
- await CallLogModel.sync({ force: true });
35
- await MessageLogModel.sync({ force: true });
36
- await UserModel.sync({ force: true });
37
- await CacheModel.sync({ force: true });
38
- await AdminConfigModel.sync({ force: true });
39
-
40
- console.log('Database models synced for testing');
41
- } catch (error) {
42
- console.error('Error setting up test database:', error);
43
- // Don't fail the setup, some tests might not need database
44
- }
45
- });
46
-
47
- // Clean up after all tests
48
- afterAll(async () => {
49
- try {
50
- // Close database connections
51
- const { sequelize } = require('../models/sequelize');
52
- if (sequelize) {
53
- await sequelize.close();
54
- }
55
- } catch (error) {
56
- console.error('Error closing database connection:', error);
57
- }
58
- });
59
-
60
- // Global test utilities
61
- global.testUtils = {
62
- // Helper to create mock user
63
- createMockUser: (overrides = {}) => ({
64
- id: 'test-user-id',
65
- platform: 'testCRM',
66
- accessToken: 'test-access-token',
67
- refreshToken: 'test-refresh-token',
68
- tokenExpiry: new Date(Date.now() + 3600000), // 1 hour from now
69
- platformUserInfo: {
70
- id: 'test-platform-user-id',
71
- name: 'Test User',
72
- timezoneName: 'America/Los_Angeles',
73
- timezoneOffset: 0,
74
- platformAdditionalInfo: {}
75
- },
76
- ...overrides
77
- }),
78
-
79
- // Helper to create mock call log
80
- createMockCallLog: (overrides = {}) => ({
81
- id: 'test-call-log-id',
82
- userId: 'test-user-id',
83
- platform: 'testCRM',
84
- thirdPartyLogId: 'test-third-party-id',
85
- contactId: 'test-contact-id',
86
- contactType: 'Contact',
87
- phoneNumber: '+1234567890',
88
- callDirection: 'Inbound',
89
- callResult: 'Answered',
90
- callDuration: 120,
91
- callStartTime: new Date(),
92
- callEndTime: new Date(Date.now() + 120000),
93
- recordingLink: 'https://example.com/recording.mp3',
94
- subject: 'Test Call',
95
- note: 'Test call note',
96
- ...overrides
97
- }),
98
-
99
- // Helper to create mock contact
100
- createMockContact: (overrides = {}) => ({
101
- id: 'test-contact-id',
102
- name: 'Test Contact',
103
- type: 'Contact',
104
- phone: '+1234567890',
105
- additionalInfo: null,
106
- ...overrides
107
- }),
108
-
109
- // Helper to reset adapter registry
110
- resetAdapterRegistry: () => {
111
- const adapterRegistry = require('../adapter/registry');
112
- adapterRegistry.adapters.clear();
113
- adapterRegistry.manifests.clear();
114
- adapterRegistry.platformInterfaces.clear();
115
- adapterRegistry.releaseNotes = {};
116
- },
117
-
118
- // Helper to create mock adapter
119
- createMockAdapter: (overrides = {}) => ({
120
- getAuthType: jest.fn().mockReturnValue('apiKey'),
121
- getUserInfo: jest.fn().mockResolvedValue({
122
- successful: true,
123
- platformUserInfo: {
124
- id: 'test-user-id',
125
- name: 'Test User',
126
- timezoneName: 'America/Los_Angeles',
127
- timezoneOffset: 0,
128
- platformAdditionalInfo: {}
129
- }
130
- }),
131
- createCallLog: jest.fn().mockResolvedValue({
132
- logId: 'test-log-id',
133
- returnMessage: {
134
- message: 'Call logged successfully',
135
- messageType: 'success',
136
- ttl: 2000
137
- }
138
- }),
139
- updateCallLog: jest.fn().mockResolvedValue({
140
- updatedNote: 'Call log updated',
141
- returnMessage: {
142
- message: 'Call log updated successfully',
143
- messageType: 'success',
144
- ttl: 2000
145
- }
146
- }),
147
- unAuthorize: jest.fn().mockResolvedValue({
148
- returnMessage: {
149
- messageType: 'success',
150
- message: 'Logged out successfully',
151
- ttl: 1000
152
- }
153
- }),
154
- findContact: jest.fn().mockResolvedValue([
155
- {
156
- id: 'test-contact-id',
157
- name: 'Test Contact',
158
- type: 'Contact',
159
- phone: '+1234567890',
160
- additionalInfo: null
161
- }
162
- ]),
163
- createContact: jest.fn().mockResolvedValue({
164
- contactInfo: {
165
- id: 'new-contact-id',
166
- name: 'New Contact'
167
- },
168
- returnMessage: {
169
- message: 'Contact created successfully',
170
- messageType: 'success',
171
- ttl: 2000
172
- }
173
- }),
174
- ...overrides
175
- })
176
- };
1
+ // Test setup for @app-connect/core package
2
+ const path = require('path');
3
+ require('dotenv').config({ path: path.resolve(__dirname, '../.env.test') });
4
+
5
+ // Set test timeout
6
+ jest.setTimeout(30000);
7
+
8
+ // Mock console methods to reduce noise in tests
9
+ global.console = {
10
+ ...console,
11
+ log: jest.fn(),
12
+ debug: jest.fn(),
13
+ info: jest.fn(),
14
+ warn: jest.fn(),
15
+ error: jest.fn(),
16
+ };
17
+
18
+ // Setup database models for testing
19
+ beforeAll(async () => {
20
+ try {
21
+ // Set up test database URL if not provided
22
+ if (!process.env.DATABASE_URL) {
23
+ process.env.DATABASE_URL = 'sqlite::memory:';
24
+ }
25
+
26
+ // Import models
27
+ const { CallLogModel } = require('../models/callLogModel');
28
+ const { MessageLogModel } = require('../models/messageLogModel');
29
+ const { UserModel } = require('../models/userModel');
30
+ const { CacheModel } = require('../models/cacheModel');
31
+ const { AdminConfigModel } = require('../models/adminConfigModel');
32
+
33
+ // Sync database models
34
+ await CallLogModel.sync({ force: true });
35
+ await MessageLogModel.sync({ force: true });
36
+ await UserModel.sync({ force: true });
37
+ await CacheModel.sync({ force: true });
38
+ await AdminConfigModel.sync({ force: true });
39
+
40
+ console.log('Database models synced for testing');
41
+ } catch (error) {
42
+ console.error('Error setting up test database:', error);
43
+ // Don't fail the setup, some tests might not need database
44
+ }
45
+ });
46
+
47
+ // Clean up after all tests
48
+ afterAll(async () => {
49
+ try {
50
+ // Close database connections
51
+ const { sequelize } = require('../models/sequelize');
52
+ if (sequelize) {
53
+ await sequelize.close();
54
+ }
55
+ } catch (error) {
56
+ console.error('Error closing database connection:', error);
57
+ }
58
+ });
59
+
60
+ // Global test utilities
61
+ global.testUtils = {
62
+ // Helper to create mock user
63
+ createMockUser: (overrides = {}) => ({
64
+ id: 'test-user-id',
65
+ platform: 'testCRM',
66
+ accessToken: 'test-access-token',
67
+ refreshToken: 'test-refresh-token',
68
+ tokenExpiry: new Date(Date.now() + 3600000), // 1 hour from now
69
+ platformUserInfo: {
70
+ id: 'test-platform-user-id',
71
+ name: 'Test User',
72
+ timezoneName: 'America/Los_Angeles',
73
+ timezoneOffset: 0,
74
+ platformAdditionalInfo: {}
75
+ },
76
+ ...overrides
77
+ }),
78
+
79
+ // Helper to create mock call log
80
+ createMockCallLog: (overrides = {}) => ({
81
+ id: 'test-call-log-id',
82
+ userId: 'test-user-id',
83
+ platform: 'testCRM',
84
+ thirdPartyLogId: 'test-third-party-id',
85
+ contactId: 'test-contact-id',
86
+ contactType: 'Contact',
87
+ phoneNumber: '+1234567890',
88
+ callDirection: 'Inbound',
89
+ callResult: 'Answered',
90
+ callDuration: 120,
91
+ callStartTime: new Date(),
92
+ callEndTime: new Date(Date.now() + 120000),
93
+ recordingLink: 'https://example.com/recording.mp3',
94
+ subject: 'Test Call',
95
+ note: 'Test call note',
96
+ ...overrides
97
+ }),
98
+
99
+ // Helper to create mock contact
100
+ createMockContact: (overrides = {}) => ({
101
+ id: 'test-contact-id',
102
+ name: 'Test Contact',
103
+ type: 'Contact',
104
+ phone: '+1234567890',
105
+ additionalInfo: null,
106
+ ...overrides
107
+ }),
108
+
109
+ // Helper to reset adapter registry
110
+ resetAdapterRegistry: () => {
111
+ const adapterRegistry = require('../adapter/registry');
112
+ adapterRegistry.adapters.clear();
113
+ adapterRegistry.manifests.clear();
114
+ adapterRegistry.platformInterfaces.clear();
115
+ adapterRegistry.releaseNotes = {};
116
+ },
117
+
118
+ // Helper to create mock adapter
119
+ createMockAdapter: (overrides = {}) => ({
120
+ getAuthType: jest.fn().mockReturnValue('apiKey'),
121
+ getUserInfo: jest.fn().mockResolvedValue({
122
+ successful: true,
123
+ platformUserInfo: {
124
+ id: 'test-user-id',
125
+ name: 'Test User',
126
+ timezoneName: 'America/Los_Angeles',
127
+ timezoneOffset: 0,
128
+ platformAdditionalInfo: {}
129
+ }
130
+ }),
131
+ createCallLog: jest.fn().mockResolvedValue({
132
+ logId: 'test-log-id',
133
+ returnMessage: {
134
+ message: 'Call logged successfully',
135
+ messageType: 'success',
136
+ ttl: 2000
137
+ }
138
+ }),
139
+ updateCallLog: jest.fn().mockResolvedValue({
140
+ updatedNote: 'Call log updated',
141
+ returnMessage: {
142
+ message: 'Call log updated successfully',
143
+ messageType: 'success',
144
+ ttl: 2000
145
+ }
146
+ }),
147
+ unAuthorize: jest.fn().mockResolvedValue({
148
+ returnMessage: {
149
+ messageType: 'success',
150
+ message: 'Logged out successfully',
151
+ ttl: 1000
152
+ }
153
+ }),
154
+ findContact: jest.fn().mockResolvedValue([
155
+ {
156
+ id: 'test-contact-id',
157
+ name: 'Test Contact',
158
+ type: 'Contact',
159
+ phone: '+1234567890',
160
+ additionalInfo: null
161
+ }
162
+ ]),
163
+ createContact: jest.fn().mockResolvedValue({
164
+ contactInfo: {
165
+ id: 'new-contact-id',
166
+ name: 'New Contact'
167
+ },
168
+ returnMessage: {
169
+ message: 'Contact created successfully',
170
+ messageType: 'success',
171
+ ttl: 2000
172
+ }
173
+ }),
174
+ ...overrides
175
+ })
176
+ };