@app-connect/core 1.7.25 → 1.7.26
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.
- package/.env.test +5 -5
- package/README.md +441 -441
- package/connector/developerPortal.js +31 -31
- package/connector/mock.js +84 -77
- package/connector/proxy/engine.js +164 -164
- package/connector/proxy/index.js +500 -500
- package/connector/registry.js +252 -252
- package/docs/README.md +50 -50
- package/docs/architecture.md +93 -93
- package/docs/connectors.md +116 -116
- package/docs/handlers.md +125 -125
- package/docs/libraries.md +101 -101
- package/docs/models.md +144 -144
- package/docs/routes.md +115 -115
- package/docs/tests.md +73 -73
- package/handlers/admin.js +523 -523
- package/handlers/appointment.js +193 -0
- package/handlers/auth.js +296 -296
- package/handlers/calldown.js +99 -99
- package/handlers/contact.js +280 -280
- package/handlers/disposition.js +82 -80
- package/handlers/log.js +984 -973
- package/handlers/managedAuth.js +446 -446
- package/handlers/plugin.js +208 -208
- package/handlers/user.js +142 -142
- package/index.js +3140 -2652
- package/jest.config.js +56 -56
- package/lib/analytics.js +54 -54
- package/lib/authSession.js +109 -109
- package/lib/cacheCleanup.js +21 -0
- package/lib/callLogComposer.js +898 -898
- package/lib/callLogLookup.js +34 -0
- package/lib/constants.js +8 -8
- package/lib/debugTracer.js +177 -177
- package/lib/encode.js +30 -30
- package/lib/errorHandler.js +218 -206
- package/lib/generalErrorMessage.js +41 -41
- package/lib/jwt.js +18 -18
- package/lib/logger.js +190 -190
- package/lib/migrateCallLogsSchema.js +116 -0
- package/lib/ringcentral.js +266 -266
- package/lib/s3ErrorLogReport.js +65 -65
- package/lib/sharedSMSComposer.js +471 -471
- package/lib/util.js +67 -67
- package/mcp/README.md +412 -395
- package/mcp/lib/validator.js +91 -91
- package/mcp/mcpHandler.js +425 -425
- package/mcp/tools/cancelAppointment.js +101 -0
- package/mcp/tools/checkAuthStatus.js +105 -105
- package/mcp/tools/confirmAppointment.js +101 -0
- package/mcp/tools/createAppointment.js +157 -0
- package/mcp/tools/createCallLog.js +327 -316
- package/mcp/tools/createContact.js +117 -117
- package/mcp/tools/createMessageLog.js +287 -287
- package/mcp/tools/doAuth.js +60 -60
- package/mcp/tools/findContactByName.js +93 -93
- package/mcp/tools/findContactByPhone.js +101 -101
- package/mcp/tools/getCallLog.js +111 -102
- package/mcp/tools/getGoogleFilePicker.js +99 -99
- package/mcp/tools/getHelp.js +43 -43
- package/mcp/tools/getPublicConnectors.js +94 -94
- package/mcp/tools/getSessionInfo.js +90 -90
- package/mcp/tools/index.js +51 -41
- package/mcp/tools/listAppointments.js +163 -0
- package/mcp/tools/logout.js +96 -96
- package/mcp/tools/rcGetCallLogs.js +65 -65
- package/mcp/tools/updateAppointment.js +154 -0
- package/mcp/tools/updateCallLog.js +130 -126
- package/mcp/ui/App/App.tsx +358 -358
- package/mcp/ui/App/components/AuthInfoForm.tsx +113 -113
- package/mcp/ui/App/components/AuthSuccess.tsx +22 -22
- package/mcp/ui/App/components/ConnectorList.tsx +82 -82
- package/mcp/ui/App/components/DebugPanel.tsx +43 -43
- package/mcp/ui/App/components/OAuthConnect.tsx +270 -270
- package/mcp/ui/App/lib/callTool.ts +130 -130
- package/mcp/ui/App/lib/debugLog.ts +41 -41
- package/mcp/ui/App/lib/developerPortal.ts +111 -111
- package/mcp/ui/App/main.css +5 -5
- package/mcp/ui/App/root.tsx +13 -13
- package/mcp/ui/index.html +13 -13
- package/mcp/ui/package-lock.json +6356 -6356
- package/mcp/ui/package.json +25 -25
- package/mcp/ui/tsconfig.json +26 -26
- package/mcp/ui/vite.config.ts +16 -16
- package/models/accountDataModel.js +33 -33
- package/models/adminConfigModel.js +35 -35
- package/models/cacheModel.js +30 -26
- package/models/callDownListModel.js +34 -34
- package/models/callLogModel.js +33 -27
- package/models/dynamo/connectorSchema.js +146 -146
- package/models/dynamo/lockSchema.js +24 -24
- package/models/dynamo/noteCacheSchema.js +29 -29
- package/models/llmSessionModel.js +17 -17
- package/models/messageLogModel.js +25 -25
- package/models/sequelize.js +16 -16
- package/models/userModel.js +45 -45
- package/package.json +1 -1
- package/releaseNotes.json +1093 -1081
- package/test/connector/proxy/engine.test.js +126 -126
- package/test/connector/proxy/index.test.js +279 -279
- package/test/connector/proxy/sample.json +161 -161
- package/test/connector/registry.test.js +415 -415
- package/test/handlers/admin.test.js +616 -616
- package/test/handlers/auth.test.js +1018 -1018
- package/test/handlers/contact.test.js +1014 -1014
- package/test/handlers/log.test.js +1298 -1160
- package/test/handlers/managedAuth.test.js +457 -457
- package/test/handlers/plugin.test.js +380 -380
- package/test/index.test.js +105 -105
- package/test/lib/cacheCleanup.test.js +42 -0
- package/test/lib/callLogComposer.test.js +1231 -1231
- package/test/lib/debugTracer.test.js +328 -328
- package/test/lib/jwt.test.js +176 -176
- package/test/lib/logger.test.js +206 -206
- package/test/lib/oauth.test.js +359 -359
- package/test/lib/ringcentral.test.js +467 -467
- package/test/lib/sharedSMSComposer.test.js +1084 -1084
- package/test/lib/util.test.js +329 -329
- package/test/mcp/tools/checkAuthStatus.test.js +83 -83
- package/test/mcp/tools/createCallLog.test.js +436 -436
- package/test/mcp/tools/createContact.test.js +58 -58
- package/test/mcp/tools/createMessageLog.test.js +595 -595
- package/test/mcp/tools/doAuth.test.js +113 -113
- package/test/mcp/tools/findContactByName.test.js +275 -275
- package/test/mcp/tools/findContactByPhone.test.js +296 -296
- package/test/mcp/tools/getCallLog.test.js +298 -298
- package/test/mcp/tools/getGoogleFilePicker.test.js +281 -281
- package/test/mcp/tools/getPublicConnectors.test.js +107 -107
- package/test/mcp/tools/getSessionInfo.test.js +127 -127
- package/test/mcp/tools/logout.test.js +233 -233
- package/test/mcp/tools/rcGetCallLogs.test.js +56 -56
- package/test/mcp/tools/updateCallLog.test.js +360 -360
- package/test/models/accountDataModel.test.js +98 -98
- package/test/models/dynamo/connectorSchema.test.js +189 -189
- package/test/models/models.test.js +568 -539
- package/test/routes/managedAuthRoutes.test.js +104 -104
- package/test/setup.js +178 -178
|
@@ -1,275 +1,275 @@
|
|
|
1
|
-
const findContactByName = require('../../../mcp/tools/findContactByName');
|
|
2
|
-
const jwt = require('../../../lib/jwt');
|
|
3
|
-
const connectorRegistry = require('../../../connector/registry');
|
|
4
|
-
const contactCore = require('../../../handlers/contact');
|
|
5
|
-
|
|
6
|
-
// Mock dependencies
|
|
7
|
-
jest.mock('../../../lib/jwt');
|
|
8
|
-
jest.mock('../../../connector/registry');
|
|
9
|
-
jest.mock('../../../handlers/contact');
|
|
10
|
-
|
|
11
|
-
describe('MCP Tool: findContactByName', () => {
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
jest.clearAllMocks();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('tool definition', () => {
|
|
17
|
-
test('should have correct tool definition', () => {
|
|
18
|
-
expect(findContactByName.definition).toBeDefined();
|
|
19
|
-
expect(findContactByName.definition.name).toBe('findContactByName');
|
|
20
|
-
expect(findContactByName.definition.description).toContain('REQUIRES CRM CONNECTION');
|
|
21
|
-
expect(findContactByName.definition.inputSchema).toBeDefined();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('should require name parameter (jwtToken is server-injected)', () => {
|
|
25
|
-
expect(findContactByName.definition.inputSchema.required).not.toContain('jwtToken');
|
|
26
|
-
expect(findContactByName.definition.inputSchema.required).toContain('name');
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('execute', () => {
|
|
31
|
-
test('should find contact by name successfully', async () => {
|
|
32
|
-
// Arrange
|
|
33
|
-
const mockContact = {
|
|
34
|
-
id: 'contact-123',
|
|
35
|
-
name: 'John Doe',
|
|
36
|
-
phone: '+1234567890',
|
|
37
|
-
type: 'Contact'
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
jwt.decodeJwt.mockReturnValue({
|
|
41
|
-
id: 'user-123',
|
|
42
|
-
platform: 'testCRM'
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const mockConnector = {
|
|
46
|
-
findContactWithName: jest.fn()
|
|
47
|
-
};
|
|
48
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
49
|
-
|
|
50
|
-
contactCore.findContactWithName.mockResolvedValue({
|
|
51
|
-
successful: true,
|
|
52
|
-
contact: mockContact,
|
|
53
|
-
returnMessage: { message: 'Contact found' }
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Act
|
|
57
|
-
const result = await findContactByName.execute({
|
|
58
|
-
jwtToken: 'mock-jwt-token',
|
|
59
|
-
name: 'John Doe'
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Assert
|
|
63
|
-
expect(result).toEqual({
|
|
64
|
-
success: true,
|
|
65
|
-
data: mockContact
|
|
66
|
-
});
|
|
67
|
-
expect(jwt.decodeJwt).toHaveBeenCalledWith('mock-jwt-token');
|
|
68
|
-
expect(connectorRegistry.getConnector).toHaveBeenCalledWith('testCRM');
|
|
69
|
-
expect(contactCore.findContactWithName).toHaveBeenCalledWith({
|
|
70
|
-
platform: 'testCRM',
|
|
71
|
-
userId: 'user-123',
|
|
72
|
-
name: 'John Doe'
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('should find contact with partial name', async () => {
|
|
77
|
-
// Arrange
|
|
78
|
-
const mockContact = {
|
|
79
|
-
id: 'contact-456',
|
|
80
|
-
name: 'Jane Smith',
|
|
81
|
-
phone: '+9876543210',
|
|
82
|
-
type: 'Contact'
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
jwt.decodeJwt.mockReturnValue({
|
|
86
|
-
id: 'user-123',
|
|
87
|
-
platform: 'testCRM'
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
const mockConnector = {
|
|
91
|
-
findContactWithName: jest.fn()
|
|
92
|
-
};
|
|
93
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
94
|
-
|
|
95
|
-
contactCore.findContactWithName.mockResolvedValue({
|
|
96
|
-
successful: true,
|
|
97
|
-
contact: mockContact
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Act
|
|
101
|
-
const result = await findContactByName.execute({
|
|
102
|
-
jwtToken: 'mock-jwt-token',
|
|
103
|
-
name: 'Jane'
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Assert
|
|
107
|
-
expect(result.success).toBe(true);
|
|
108
|
-
expect(result.data).toEqual(mockContact);
|
|
109
|
-
expect(contactCore.findContactWithName).toHaveBeenCalledWith({
|
|
110
|
-
platform: 'testCRM',
|
|
111
|
-
userId: 'user-123',
|
|
112
|
-
name: 'Jane'
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test('should return error when contact not found', async () => {
|
|
117
|
-
// Arrange
|
|
118
|
-
jwt.decodeJwt.mockReturnValue({
|
|
119
|
-
id: 'user-123',
|
|
120
|
-
platform: 'testCRM'
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const mockConnector = {
|
|
124
|
-
findContactWithName: jest.fn()
|
|
125
|
-
};
|
|
126
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
127
|
-
|
|
128
|
-
contactCore.findContactWithName.mockResolvedValue({
|
|
129
|
-
successful: false,
|
|
130
|
-
contact: null,
|
|
131
|
-
returnMessage: { message: 'Contact not found' }
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// Act
|
|
135
|
-
const result = await findContactByName.execute({
|
|
136
|
-
jwtToken: 'mock-jwt-token',
|
|
137
|
-
name: 'NonExistent Person'
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
// Assert
|
|
141
|
-
expect(result).toEqual({
|
|
142
|
-
success: false,
|
|
143
|
-
error: 'Contact not found'
|
|
144
|
-
});
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
test('should return error when JWT is invalid', async () => {
|
|
148
|
-
// Arrange
|
|
149
|
-
jwt.decodeJwt.mockReturnValue({
|
|
150
|
-
platform: 'testCRM'
|
|
151
|
-
// id is missing
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// Act
|
|
155
|
-
const result = await findContactByName.execute({
|
|
156
|
-
jwtToken: 'invalid-token',
|
|
157
|
-
name: 'John Doe'
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// Assert
|
|
161
|
-
expect(result.success).toBe(false);
|
|
162
|
-
expect(result.error).toContain('Invalid JWT token');
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
test('should return error when decodeJwt returns null', async () => {
|
|
166
|
-
jwt.decodeJwt.mockReturnValue(null);
|
|
167
|
-
|
|
168
|
-
const result = await findContactByName.execute({
|
|
169
|
-
jwtToken: 'invalid-token',
|
|
170
|
-
name: 'John Doe'
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
expect(result.success).toBe(false);
|
|
174
|
-
expect(result.error).toContain('Invalid JWT token');
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test('should return error when platform connector not found', async () => {
|
|
178
|
-
// Arrange
|
|
179
|
-
jwt.decodeJwt.mockReturnValue({
|
|
180
|
-
id: 'user-123',
|
|
181
|
-
platform: 'unknownCRM'
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
connectorRegistry.getConnector.mockReturnValue(null);
|
|
185
|
-
|
|
186
|
-
// Act
|
|
187
|
-
const result = await findContactByName.execute({
|
|
188
|
-
jwtToken: 'mock-jwt-token',
|
|
189
|
-
name: 'John Doe'
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// Assert
|
|
193
|
-
expect(result.success).toBe(false);
|
|
194
|
-
expect(result.error).toContain('Platform connector not found');
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test('should return error when findContactWithName is not implemented', async () => {
|
|
198
|
-
// Arrange
|
|
199
|
-
jwt.decodeJwt.mockReturnValue({
|
|
200
|
-
id: 'user-123',
|
|
201
|
-
platform: 'testCRM'
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
const mockConnector = {}; // No findContactWithName method
|
|
205
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
206
|
-
|
|
207
|
-
// Act
|
|
208
|
-
const result = await findContactByName.execute({
|
|
209
|
-
jwtToken: 'mock-jwt-token',
|
|
210
|
-
name: 'John Doe'
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// Assert
|
|
214
|
-
expect(result.success).toBe(false);
|
|
215
|
-
expect(result.error).toContain('not implemented');
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
test('should handle unexpected errors gracefully', async () => {
|
|
219
|
-
// Arrange
|
|
220
|
-
jwt.decodeJwt.mockReturnValue({
|
|
221
|
-
id: 'user-123',
|
|
222
|
-
platform: 'testCRM'
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
const mockConnector = {
|
|
226
|
-
findContactWithName: jest.fn()
|
|
227
|
-
};
|
|
228
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
229
|
-
|
|
230
|
-
contactCore.findContactWithName.mockRejectedValue(
|
|
231
|
-
new Error('API rate limit exceeded')
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
// Act
|
|
235
|
-
const result = await findContactByName.execute({
|
|
236
|
-
jwtToken: 'mock-jwt-token',
|
|
237
|
-
name: 'John Doe'
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
// Assert
|
|
241
|
-
expect(result.success).toBe(false);
|
|
242
|
-
expect(result.error).toBe('API rate limit exceeded');
|
|
243
|
-
expect(result.errorDetails).toBeDefined();
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
test('should handle empty name parameter', async () => {
|
|
247
|
-
// Arrange
|
|
248
|
-
jwt.decodeJwt.mockReturnValue({
|
|
249
|
-
id: 'user-123',
|
|
250
|
-
platform: 'testCRM'
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
const mockConnector = {
|
|
254
|
-
findContactWithName: jest.fn()
|
|
255
|
-
};
|
|
256
|
-
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
257
|
-
|
|
258
|
-
contactCore.findContactWithName.mockResolvedValue({
|
|
259
|
-
successful: false,
|
|
260
|
-
returnMessage: { message: 'Name parameter is required' }
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// Act
|
|
264
|
-
const result = await findContactByName.execute({
|
|
265
|
-
jwtToken: 'mock-jwt-token',
|
|
266
|
-
name: ''
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Assert
|
|
270
|
-
expect(result.success).toBe(false);
|
|
271
|
-
expect(result.error).toBe('Name parameter is required');
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
|
|
1
|
+
const findContactByName = require('../../../mcp/tools/findContactByName');
|
|
2
|
+
const jwt = require('../../../lib/jwt');
|
|
3
|
+
const connectorRegistry = require('../../../connector/registry');
|
|
4
|
+
const contactCore = require('../../../handlers/contact');
|
|
5
|
+
|
|
6
|
+
// Mock dependencies
|
|
7
|
+
jest.mock('../../../lib/jwt');
|
|
8
|
+
jest.mock('../../../connector/registry');
|
|
9
|
+
jest.mock('../../../handlers/contact');
|
|
10
|
+
|
|
11
|
+
describe('MCP Tool: findContactByName', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('tool definition', () => {
|
|
17
|
+
test('should have correct tool definition', () => {
|
|
18
|
+
expect(findContactByName.definition).toBeDefined();
|
|
19
|
+
expect(findContactByName.definition.name).toBe('findContactByName');
|
|
20
|
+
expect(findContactByName.definition.description).toContain('REQUIRES CRM CONNECTION');
|
|
21
|
+
expect(findContactByName.definition.inputSchema).toBeDefined();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should require name parameter (jwtToken is server-injected)', () => {
|
|
25
|
+
expect(findContactByName.definition.inputSchema.required).not.toContain('jwtToken');
|
|
26
|
+
expect(findContactByName.definition.inputSchema.required).toContain('name');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('execute', () => {
|
|
31
|
+
test('should find contact by name successfully', async () => {
|
|
32
|
+
// Arrange
|
|
33
|
+
const mockContact = {
|
|
34
|
+
id: 'contact-123',
|
|
35
|
+
name: 'John Doe',
|
|
36
|
+
phone: '+1234567890',
|
|
37
|
+
type: 'Contact'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
jwt.decodeJwt.mockReturnValue({
|
|
41
|
+
id: 'user-123',
|
|
42
|
+
platform: 'testCRM'
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const mockConnector = {
|
|
46
|
+
findContactWithName: jest.fn()
|
|
47
|
+
};
|
|
48
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
49
|
+
|
|
50
|
+
contactCore.findContactWithName.mockResolvedValue({
|
|
51
|
+
successful: true,
|
|
52
|
+
contact: mockContact,
|
|
53
|
+
returnMessage: { message: 'Contact found' }
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Act
|
|
57
|
+
const result = await findContactByName.execute({
|
|
58
|
+
jwtToken: 'mock-jwt-token',
|
|
59
|
+
name: 'John Doe'
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Assert
|
|
63
|
+
expect(result).toEqual({
|
|
64
|
+
success: true,
|
|
65
|
+
data: mockContact
|
|
66
|
+
});
|
|
67
|
+
expect(jwt.decodeJwt).toHaveBeenCalledWith('mock-jwt-token');
|
|
68
|
+
expect(connectorRegistry.getConnector).toHaveBeenCalledWith('testCRM');
|
|
69
|
+
expect(contactCore.findContactWithName).toHaveBeenCalledWith({
|
|
70
|
+
platform: 'testCRM',
|
|
71
|
+
userId: 'user-123',
|
|
72
|
+
name: 'John Doe'
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('should find contact with partial name', async () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const mockContact = {
|
|
79
|
+
id: 'contact-456',
|
|
80
|
+
name: 'Jane Smith',
|
|
81
|
+
phone: '+9876543210',
|
|
82
|
+
type: 'Contact'
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
jwt.decodeJwt.mockReturnValue({
|
|
86
|
+
id: 'user-123',
|
|
87
|
+
platform: 'testCRM'
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const mockConnector = {
|
|
91
|
+
findContactWithName: jest.fn()
|
|
92
|
+
};
|
|
93
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
94
|
+
|
|
95
|
+
contactCore.findContactWithName.mockResolvedValue({
|
|
96
|
+
successful: true,
|
|
97
|
+
contact: mockContact
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Act
|
|
101
|
+
const result = await findContactByName.execute({
|
|
102
|
+
jwtToken: 'mock-jwt-token',
|
|
103
|
+
name: 'Jane'
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Assert
|
|
107
|
+
expect(result.success).toBe(true);
|
|
108
|
+
expect(result.data).toEqual(mockContact);
|
|
109
|
+
expect(contactCore.findContactWithName).toHaveBeenCalledWith({
|
|
110
|
+
platform: 'testCRM',
|
|
111
|
+
userId: 'user-123',
|
|
112
|
+
name: 'Jane'
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('should return error when contact not found', async () => {
|
|
117
|
+
// Arrange
|
|
118
|
+
jwt.decodeJwt.mockReturnValue({
|
|
119
|
+
id: 'user-123',
|
|
120
|
+
platform: 'testCRM'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const mockConnector = {
|
|
124
|
+
findContactWithName: jest.fn()
|
|
125
|
+
};
|
|
126
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
127
|
+
|
|
128
|
+
contactCore.findContactWithName.mockResolvedValue({
|
|
129
|
+
successful: false,
|
|
130
|
+
contact: null,
|
|
131
|
+
returnMessage: { message: 'Contact not found' }
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Act
|
|
135
|
+
const result = await findContactByName.execute({
|
|
136
|
+
jwtToken: 'mock-jwt-token',
|
|
137
|
+
name: 'NonExistent Person'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Assert
|
|
141
|
+
expect(result).toEqual({
|
|
142
|
+
success: false,
|
|
143
|
+
error: 'Contact not found'
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('should return error when JWT is invalid', async () => {
|
|
148
|
+
// Arrange
|
|
149
|
+
jwt.decodeJwt.mockReturnValue({
|
|
150
|
+
platform: 'testCRM'
|
|
151
|
+
// id is missing
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Act
|
|
155
|
+
const result = await findContactByName.execute({
|
|
156
|
+
jwtToken: 'invalid-token',
|
|
157
|
+
name: 'John Doe'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Assert
|
|
161
|
+
expect(result.success).toBe(false);
|
|
162
|
+
expect(result.error).toContain('Invalid JWT token');
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('should return error when decodeJwt returns null', async () => {
|
|
166
|
+
jwt.decodeJwt.mockReturnValue(null);
|
|
167
|
+
|
|
168
|
+
const result = await findContactByName.execute({
|
|
169
|
+
jwtToken: 'invalid-token',
|
|
170
|
+
name: 'John Doe'
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
expect(result.success).toBe(false);
|
|
174
|
+
expect(result.error).toContain('Invalid JWT token');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test('should return error when platform connector not found', async () => {
|
|
178
|
+
// Arrange
|
|
179
|
+
jwt.decodeJwt.mockReturnValue({
|
|
180
|
+
id: 'user-123',
|
|
181
|
+
platform: 'unknownCRM'
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
connectorRegistry.getConnector.mockReturnValue(null);
|
|
185
|
+
|
|
186
|
+
// Act
|
|
187
|
+
const result = await findContactByName.execute({
|
|
188
|
+
jwtToken: 'mock-jwt-token',
|
|
189
|
+
name: 'John Doe'
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Assert
|
|
193
|
+
expect(result.success).toBe(false);
|
|
194
|
+
expect(result.error).toContain('Platform connector not found');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('should return error when findContactWithName is not implemented', async () => {
|
|
198
|
+
// Arrange
|
|
199
|
+
jwt.decodeJwt.mockReturnValue({
|
|
200
|
+
id: 'user-123',
|
|
201
|
+
platform: 'testCRM'
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
const mockConnector = {}; // No findContactWithName method
|
|
205
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
206
|
+
|
|
207
|
+
// Act
|
|
208
|
+
const result = await findContactByName.execute({
|
|
209
|
+
jwtToken: 'mock-jwt-token',
|
|
210
|
+
name: 'John Doe'
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Assert
|
|
214
|
+
expect(result.success).toBe(false);
|
|
215
|
+
expect(result.error).toContain('not implemented');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('should handle unexpected errors gracefully', async () => {
|
|
219
|
+
// Arrange
|
|
220
|
+
jwt.decodeJwt.mockReturnValue({
|
|
221
|
+
id: 'user-123',
|
|
222
|
+
platform: 'testCRM'
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const mockConnector = {
|
|
226
|
+
findContactWithName: jest.fn()
|
|
227
|
+
};
|
|
228
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
229
|
+
|
|
230
|
+
contactCore.findContactWithName.mockRejectedValue(
|
|
231
|
+
new Error('API rate limit exceeded')
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// Act
|
|
235
|
+
const result = await findContactByName.execute({
|
|
236
|
+
jwtToken: 'mock-jwt-token',
|
|
237
|
+
name: 'John Doe'
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Assert
|
|
241
|
+
expect(result.success).toBe(false);
|
|
242
|
+
expect(result.error).toBe('API rate limit exceeded');
|
|
243
|
+
expect(result.errorDetails).toBeDefined();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test('should handle empty name parameter', async () => {
|
|
247
|
+
// Arrange
|
|
248
|
+
jwt.decodeJwt.mockReturnValue({
|
|
249
|
+
id: 'user-123',
|
|
250
|
+
platform: 'testCRM'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const mockConnector = {
|
|
254
|
+
findContactWithName: jest.fn()
|
|
255
|
+
};
|
|
256
|
+
connectorRegistry.getConnector.mockReturnValue(mockConnector);
|
|
257
|
+
|
|
258
|
+
contactCore.findContactWithName.mockResolvedValue({
|
|
259
|
+
successful: false,
|
|
260
|
+
returnMessage: { message: 'Name parameter is required' }
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Act
|
|
264
|
+
const result = await findContactByName.execute({
|
|
265
|
+
jwtToken: 'mock-jwt-token',
|
|
266
|
+
name: ''
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Assert
|
|
270
|
+
expect(result.success).toBe(false);
|
|
271
|
+
expect(result.error).toBe('Name parameter is required');
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|