@app-connect/core 1.7.36 → 1.7.38

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 (287) hide show
  1. package/README.md +17 -16
  2. package/dist/connector/developerPortal.d.ts +6 -0
  3. package/{connector → dist/connector}/developerPortal.js +29 -12
  4. package/dist/connector/mock.d.ts +1 -0
  5. package/{connector → dist/connector}/mock.js +33 -17
  6. package/dist/connector/proxy/engine.d.ts +10 -0
  7. package/dist/connector/proxy/engine.js +222 -0
  8. package/dist/connector/proxy/index.d.ts +5 -0
  9. package/dist/connector/proxy/index.js +511 -0
  10. package/dist/connector/registry.d.ts +1 -0
  11. package/dist/connector/registry.js +243 -0
  12. package/dist/handlers/admin.d.ts +1 -0
  13. package/{handlers → dist/handlers}/admin.js +137 -78
  14. package/dist/handlers/appointment.d.ts +9 -0
  15. package/{handlers → dist/handlers}/appointment.js +58 -29
  16. package/dist/handlers/auth.d.ts +9 -0
  17. package/{handlers → dist/handlers}/auth.js +68 -40
  18. package/dist/handlers/calldown.d.ts +10 -0
  19. package/dist/handlers/calldown.js +134 -0
  20. package/dist/handlers/contact.d.ts +1 -0
  21. package/{handlers → dist/handlers}/contact.js +61 -39
  22. package/dist/handlers/disposition.d.ts +1 -0
  23. package/{handlers → dist/handlers}/disposition.js +20 -10
  24. package/dist/handlers/log.d.ts +1 -0
  25. package/{handlers → dist/handlers}/log.js +91 -124
  26. package/dist/handlers/managedAuth.d.ts +1 -0
  27. package/{handlers → dist/handlers}/managedAuth.js +134 -61
  28. package/dist/handlers/managedOAuth.d.ts +13 -0
  29. package/{handlers → dist/handlers}/managedOAuth.js +102 -30
  30. package/dist/handlers/plugin.d.ts +1 -0
  31. package/{handlers → dist/handlers}/plugin.js +59 -27
  32. package/dist/handlers/user.d.ts +1 -0
  33. package/{handlers → dist/handlers}/user.js +45 -27
  34. package/dist/index.d.ts +1 -0
  35. package/{index.js → dist/index.js} +548 -450
  36. package/dist/jest.config.d.ts +1 -0
  37. package/dist/jest.config.js +65 -0
  38. package/dist/lib/analytics.d.ts +4 -0
  39. package/{lib → dist/lib}/analytics.js +8 -6
  40. package/dist/lib/authSession.d.ts +5 -0
  41. package/{lib → dist/lib}/authSession.js +15 -43
  42. package/dist/lib/cacheCleanup.d.ts +4 -0
  43. package/{lib → dist/lib}/cacheCleanup.js +5 -17
  44. package/dist/lib/callLogComposer.d.ts +109 -0
  45. package/{lib → dist/lib}/callLogComposer.js +157 -197
  46. package/dist/lib/callLogLookup.d.ts +6 -0
  47. package/{lib → dist/lib}/callLogLookup.js +12 -34
  48. package/dist/lib/constants.d.ts +6 -0
  49. package/dist/lib/constants.js +9 -0
  50. package/dist/lib/debugTracer.d.ts +17 -0
  51. package/{lib → dist/lib}/debugTracer.js +7 -83
  52. package/dist/lib/encode.d.ts +3 -0
  53. package/dist/lib/encode.js +50 -0
  54. package/dist/lib/errorHandler.d.ts +7 -0
  55. package/dist/lib/errorHandler.js +161 -0
  56. package/dist/lib/generalErrorMessage.d.ts +7 -0
  57. package/{lib → dist/lib}/generalErrorMessage.js +6 -6
  58. package/dist/lib/jwt.d.ts +4 -0
  59. package/dist/lib/jwt.js +18 -0
  60. package/dist/lib/logger.d.ts +24 -0
  61. package/dist/lib/logger.js +126 -0
  62. package/dist/lib/migrateCallLogsSchema.d.ts +32 -0
  63. package/dist/lib/migrateCallLogsSchema.js +339 -0
  64. package/dist/lib/oauth.d.ts +4 -0
  65. package/{lib → dist/lib}/oauth.js +157 -160
  66. package/dist/lib/ringcentral.d.ts +24 -0
  67. package/dist/lib/ringcentral.js +226 -0
  68. package/dist/lib/s3ErrorLogReport.d.ts +4 -0
  69. package/{lib → dist/lib}/s3ErrorLogReport.js +11 -23
  70. package/dist/lib/sharedSMSComposer.d.ts +7 -0
  71. package/{lib → dist/lib}/sharedSMSComposer.js +21 -107
  72. package/dist/lib/util.d.ts +7 -0
  73. package/{lib → dist/lib}/util.js +9 -20
  74. package/dist/mcp/lib/oauthError.d.ts +1 -0
  75. package/dist/mcp/lib/oauthError.js +25 -0
  76. package/dist/mcp/lib/validator.d.ts +1 -0
  77. package/{mcp → dist/mcp}/lib/validator.js +16 -20
  78. package/dist/mcp/lib/widgetSessionToken.d.ts +1 -0
  79. package/dist/mcp/lib/widgetSessionToken.js +46 -0
  80. package/dist/mcp/mcpHandler.d.ts +8 -0
  81. package/{mcp → dist/mcp}/mcpHandler.js +98 -88
  82. package/dist/mcp/tools/cancelAppointment.d.ts +1 -0
  83. package/{mcp → dist/mcp}/tools/cancelAppointment.js +7 -16
  84. package/dist/mcp/tools/checkAuthStatus.d.ts +1 -0
  85. package/{mcp → dist/mcp}/tools/checkAuthStatus.js +21 -14
  86. package/dist/mcp/tools/confirmAppointment.d.ts +1 -0
  87. package/{mcp → dist/mcp}/tools/confirmAppointment.js +7 -16
  88. package/dist/mcp/tools/createAppointment.d.ts +1 -0
  89. package/{mcp → dist/mcp}/tools/createAppointment.js +7 -19
  90. package/dist/mcp/tools/createCallLog.d.ts +1 -0
  91. package/{mcp → dist/mcp}/tools/createCallLog.js +18 -29
  92. package/dist/mcp/tools/createContact.d.ts +1 -0
  93. package/{mcp → dist/mcp}/tools/createContact.js +8 -20
  94. package/dist/mcp/tools/createMessageLog.d.ts +1 -0
  95. package/{mcp → dist/mcp}/tools/createMessageLog.js +14 -26
  96. package/dist/mcp/tools/doAuth.d.ts +1 -0
  97. package/{mcp → dist/mcp}/tools/doAuth.js +17 -13
  98. package/dist/mcp/tools/findContactByName.d.ts +1 -0
  99. package/{mcp → dist/mcp}/tools/findContactByName.js +9 -15
  100. package/dist/mcp/tools/findContactByPhone.d.ts +1 -0
  101. package/{mcp → dist/mcp}/tools/findContactByPhone.js +8 -15
  102. package/dist/mcp/tools/getCallLog.d.ts +1 -0
  103. package/{mcp → dist/mcp}/tools/getCallLog.js +12 -21
  104. package/dist/mcp/tools/getGoogleFilePicker.d.ts +1 -0
  105. package/{mcp → dist/mcp}/tools/getGoogleFilePicker.js +9 -18
  106. package/dist/mcp/tools/getHelp.d.ts +1 -0
  107. package/{mcp → dist/mcp}/tools/getHelp.js +5 -6
  108. package/dist/mcp/tools/getPublicConnectors.d.ts +1 -0
  109. package/{mcp → dist/mcp}/tools/getPublicConnectors.js +19 -18
  110. package/dist/mcp/tools/getSessionInfo.d.ts +1 -0
  111. package/{mcp → dist/mcp}/tools/getSessionInfo.js +10 -16
  112. package/dist/mcp/tools/index.d.ts +8 -0
  113. package/dist/mcp/tools/index.js +50 -0
  114. package/dist/mcp/tools/listAppointments.d.ts +1 -0
  115. package/{mcp → dist/mcp}/tools/listAppointments.js +7 -19
  116. package/dist/mcp/tools/logout.d.ts +1 -0
  117. package/{mcp → dist/mcp}/tools/logout.js +16 -14
  118. package/dist/mcp/tools/rcGetCallLogs.d.ts +1 -0
  119. package/{mcp → dist/mcp}/tools/rcGetCallLogs.js +10 -8
  120. package/dist/mcp/tools/updateAppointment.d.ts +1 -0
  121. package/{mcp → dist/mcp}/tools/updateAppointment.js +17 -22
  122. package/dist/mcp/tools/updateCallLog.d.ts +1 -0
  123. package/{mcp → dist/mcp}/tools/updateCallLog.js +16 -26
  124. package/dist/models/accountDataModel.d.ts +3 -0
  125. package/dist/models/accountDataModel.js +39 -0
  126. package/dist/models/adminConfigModel.d.ts +2 -0
  127. package/dist/models/adminConfigModel.js +39 -0
  128. package/dist/models/cacheModel.d.ts +2 -0
  129. package/{models → dist/models}/cacheModel.js +7 -3
  130. package/dist/models/callDownListModel.d.ts +2 -0
  131. package/{models → dist/models}/callDownListModel.js +8 -4
  132. package/dist/models/callLogModel.d.ts +2 -0
  133. package/dist/models/callLogModel.js +43 -0
  134. package/dist/models/dynamo/connectorSchema.d.ts +2 -0
  135. package/dist/models/dynamo/connectorSchema.js +141 -0
  136. package/dist/models/dynamo/lockSchema.d.ts +2 -0
  137. package/{models → dist/models}/dynamo/lockSchema.js +5 -7
  138. package/dist/models/dynamo/noteCacheSchema.d.ts +2 -0
  139. package/{models → dist/models}/dynamo/noteCacheSchema.js +4 -6
  140. package/dist/models/llmSessionModel.d.ts +2 -0
  141. package/dist/models/llmSessionModel.js +21 -0
  142. package/dist/models/messageLogModel.d.ts +2 -0
  143. package/{models → dist/models}/messageLogModel.js +8 -4
  144. package/dist/models/sequelize.d.ts +2 -0
  145. package/dist/models/sequelize.js +68 -0
  146. package/dist/models/userModel.d.ts +2 -0
  147. package/dist/models/userModel.js +49 -0
  148. package/dist/package.json +100 -0
  149. package/dist/releaseNotes.json +1222 -0
  150. package/dist/tsconfig.json +14 -0
  151. package/dist/types/admin.d.ts +141 -0
  152. package/dist/types/analytics.d.ts +14 -0
  153. package/dist/types/appointment.d.ts +50 -0
  154. package/dist/types/auth.d.ts +137 -0
  155. package/dist/types/authSession.d.ts +35 -0
  156. package/dist/types/cacheCleanup.d.ts +12 -0
  157. package/dist/types/calldown.d.ts +54 -0
  158. package/dist/types/common.d.ts +46 -0
  159. package/dist/types/connector.d.ts +165 -0
  160. package/dist/types/contact.d.ts +125 -0
  161. package/dist/types/errorHandler.d.ts +60 -0
  162. package/dist/types/index.d.ts +76 -0
  163. package/dist/types/json.d.ts +9 -0
  164. package/dist/types/jwt.d.ts +8 -0
  165. package/dist/types/logging.d.ts +224 -0
  166. package/dist/types/managedAuth.d.ts +114 -0
  167. package/dist/types/managedOAuth.d.ts +59 -0
  168. package/dist/types/manifest.d.ts +120 -0
  169. package/dist/types/migration.d.ts +15 -0
  170. package/dist/types/plugin.d.ts +74 -0
  171. package/dist/types/ringcentral.d.ts +61 -0
  172. package/dist/types/s3ErrorLogReport.d.ts +16 -0
  173. package/dist/types/sharedSMSComposer.d.ts +105 -0
  174. package/dist/types/user.d.ts +46 -0
  175. package/dist/types/util.d.ts +7 -0
  176. package/package.json +34 -6
  177. package/releaseNotes.json +13 -1
  178. package/.env.test +0 -5
  179. package/connector/proxy/engine.js +0 -165
  180. package/connector/proxy/index.js +0 -500
  181. package/connector/registry.js +0 -252
  182. package/docs/README.md +0 -50
  183. package/docs/architecture.md +0 -94
  184. package/docs/connectors.md +0 -116
  185. package/docs/handlers.md +0 -128
  186. package/docs/libraries.md +0 -98
  187. package/docs/models.md +0 -146
  188. package/docs/routes.md +0 -119
  189. package/docs/tests.md +0 -73
  190. package/handlers/calldown.js +0 -99
  191. package/jest.config.js +0 -57
  192. package/lib/constants.js +0 -9
  193. package/lib/encode.js +0 -30
  194. package/lib/errorHandler.js +0 -218
  195. package/lib/jwt.js +0 -18
  196. package/lib/logger.js +0 -190
  197. package/lib/migrateCallLogsSchema.js +0 -237
  198. package/lib/ringcentral.js +0 -267
  199. package/mcp/README.md +0 -420
  200. package/mcp/tools/index.js +0 -51
  201. package/mcp/ui/App/App.tsx +0 -358
  202. package/mcp/ui/App/components/AuthInfoForm.tsx +0 -113
  203. package/mcp/ui/App/components/AuthSuccess.tsx +0 -22
  204. package/mcp/ui/App/components/ConnectorList.tsx +0 -82
  205. package/mcp/ui/App/components/DebugPanel.tsx +0 -43
  206. package/mcp/ui/App/components/OAuthConnect.tsx +0 -270
  207. package/mcp/ui/App/lib/callTool.ts +0 -130
  208. package/mcp/ui/App/lib/debugLog.ts +0 -41
  209. package/mcp/ui/App/lib/developerPortal.ts +0 -111
  210. package/mcp/ui/App/main.css +0 -6
  211. package/mcp/ui/App/root.tsx +0 -13
  212. package/mcp/ui/dist/index.html +0 -53
  213. package/mcp/ui/vite.config.ts +0 -16
  214. package/models/accountDataModel.js +0 -34
  215. package/models/adminConfigModel.js +0 -35
  216. package/models/callLogModel.js +0 -39
  217. package/models/dynamo/connectorSchema.js +0 -146
  218. package/models/llmSessionModel.js +0 -17
  219. package/models/sequelize.js +0 -17
  220. package/models/userModel.js +0 -45
  221. package/test/connector/developerPortal.test.js +0 -166
  222. package/test/connector/mock.test.js +0 -131
  223. package/test/connector/proxy/engine.test.js +0 -211
  224. package/test/connector/proxy/index.test.js +0 -525
  225. package/test/connector/proxy/sample.json +0 -162
  226. package/test/connector/registry.test.js +0 -416
  227. package/test/handlers/admin.test.js +0 -960
  228. package/test/handlers/appointment.test.js +0 -260
  229. package/test/handlers/auth.test.js +0 -1096
  230. package/test/handlers/calldown.test.js +0 -310
  231. package/test/handlers/contact.test.js +0 -1014
  232. package/test/handlers/disposition.test.js +0 -396
  233. package/test/handlers/log.test.js +0 -1847
  234. package/test/handlers/managedAuth.test.js +0 -458
  235. package/test/handlers/managedOAuth.test.js +0 -262
  236. package/test/handlers/plugin.test.js +0 -429
  237. package/test/handlers/user.test.js +0 -381
  238. package/test/index.test.js +0 -301
  239. package/test/lib/analytics.test.js +0 -146
  240. package/test/lib/authSession.test.js +0 -173
  241. package/test/lib/cacheCleanup.test.js +0 -127
  242. package/test/lib/callLogComposer.test.js +0 -1231
  243. package/test/lib/debugTracer.test.js +0 -328
  244. package/test/lib/encode.test.js +0 -59
  245. package/test/lib/errorHandler.test.js +0 -246
  246. package/test/lib/generalErrorMessage.test.js +0 -82
  247. package/test/lib/jwt.test.js +0 -176
  248. package/test/lib/logger.test.js +0 -206
  249. package/test/lib/oauth.test.js +0 -359
  250. package/test/lib/ringcentral.test.js +0 -467
  251. package/test/lib/s3ErrorLogReport.test.js +0 -187
  252. package/test/lib/sharedSMSComposer.test.js +0 -1084
  253. package/test/lib/util.test.js +0 -329
  254. package/test/mcp/mcpHandler.test.js +0 -73
  255. package/test/mcp/mcpHandlerMore.test.js +0 -384
  256. package/test/mcp/tools/appointmentTools.test.js +0 -362
  257. package/test/mcp/tools/checkAuthStatus.test.js +0 -83
  258. package/test/mcp/tools/createCallLog.test.js +0 -436
  259. package/test/mcp/tools/createContact.test.js +0 -58
  260. package/test/mcp/tools/createMessageLog.test.js +0 -595
  261. package/test/mcp/tools/doAuth.test.js +0 -113
  262. package/test/mcp/tools/findContactByName.test.js +0 -275
  263. package/test/mcp/tools/findContactByPhone.test.js +0 -296
  264. package/test/mcp/tools/getCallLog.test.js +0 -298
  265. package/test/mcp/tools/getGoogleFilePicker.test.js +0 -281
  266. package/test/mcp/tools/getPublicConnectors.test.js +0 -107
  267. package/test/mcp/tools/getSessionInfo.test.js +0 -127
  268. package/test/mcp/tools/logout.test.js +0 -233
  269. package/test/mcp/tools/rcGetCallLogs.test.js +0 -56
  270. package/test/mcp/tools/updateCallLog.test.js +0 -360
  271. package/test/models/accountDataModel.test.js +0 -98
  272. package/test/models/callDownListModel.test.js +0 -125
  273. package/test/models/dynamo/connectorSchema.test.js +0 -189
  274. package/test/models/dynamo/lockSchema.test.js +0 -37
  275. package/test/models/dynamo/noteCacheSchema.test.js +0 -45
  276. package/test/models/llmSessionModel.test.js +0 -91
  277. package/test/models/models.test.js +0 -660
  278. package/test/routes/calldownRoutes.test.js +0 -224
  279. package/test/routes/coreRouterBroadRoutes.test.js +0 -855
  280. package/test/routes/dispositionRoutes.test.js +0 -192
  281. package/test/routes/managedAuthRoutes.test.js +0 -386
  282. package/test/routes/pluginRoutes.test.js +0 -262
  283. package/test/setup.js +0 -178
  284. /package/{mcp → dist/mcp}/ui/index.html +0 -0
  285. /package/{mcp → dist/mcp}/ui/package-lock.json +0 -0
  286. /package/{mcp → dist/mcp}/ui/package.json +0 -0
  287. /package/{mcp → dist/mcp}/ui/tsconfig.json +0 -0
@@ -1,1014 +0,0 @@
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
- jest.mock('../../connector/registry');
14
- jest.mock('../../lib/oauth');
15
- jest.mock('../../models/dynamo/connectorSchema', () => ({
16
- Connector: {
17
- getProxyConfig: jest.fn()
18
- }
19
- }));
20
-
21
- const contactHandler = require('../../handlers/contact');
22
- const { UserModel } = require('../../models/userModel');
23
- const { AccountDataModel } = require('../../models/accountDataModel');
24
- const connectorRegistry = require('../../connector/registry');
25
- const oauth = require('../../lib/oauth');
26
- const { Connector } = require('../../models/dynamo/connectorSchema');
27
- const { sequelize } = require('../../models/sequelize');
28
-
29
- describe('Contact Handler', () => {
30
- beforeAll(async () => {
31
- await UserModel.sync({ force: true });
32
- await AccountDataModel.sync({ force: true });
33
- });
34
-
35
- afterEach(async () => {
36
- await UserModel.destroy({ where: {} });
37
- await AccountDataModel.destroy({ where: {} });
38
- jest.clearAllMocks();
39
- });
40
-
41
- afterAll(async () => {
42
- await sequelize.close();
43
- });
44
-
45
- describe('findContact', () => {
46
- const mockUser = {
47
- id: 'test-user-id',
48
- platform: 'testCRM',
49
- accessToken: 'test-access-token',
50
- rcAccountId: 'rc-account-123',
51
- platformAdditionalInfo: {}
52
- };
53
-
54
- test('should return warning when user not found', async () => {
55
- // Act
56
- const result = await contactHandler.findContact({
57
- platform: 'testCRM',
58
- userId: 'non-existent-user',
59
- phoneNumber: '+1234567890'
60
- });
61
-
62
- // Assert
63
- expect(result.successful).toBe(false);
64
- expect(result.returnMessage.message).toBe('Contact not found');
65
- expect(result.returnMessage.messageType).toBe('warning');
66
- });
67
-
68
- test('should return warning when user has no access token', async () => {
69
- // Arrange
70
- await UserModel.create({
71
- id: 'test-user-id',
72
- platform: 'testCRM',
73
- accessToken: null
74
- });
75
-
76
- // Act
77
- const result = await contactHandler.findContact({
78
- platform: 'testCRM',
79
- userId: 'test-user-id',
80
- phoneNumber: '+1234567890'
81
- });
82
-
83
- // Assert
84
- expect(result.successful).toBe(false);
85
- expect(result.returnMessage.message).toBe('Contact not found');
86
- });
87
-
88
- test('should return cached contact when available', async () => {
89
- // Arrange
90
- await UserModel.create(mockUser);
91
-
92
- const cachedContact = [
93
- { id: 'contact-1', name: 'Cached Contact', type: 'Contact', phone: '+1234567890' }
94
- ];
95
- await AccountDataModel.create({
96
- rcAccountId: 'rc-account-123',
97
- platformName: 'testCRM',
98
- dataKey: 'contact-+1234567890',
99
- data: cachedContact
100
- });
101
-
102
- // Act
103
- const result = await contactHandler.findContact({
104
- platform: 'testCRM',
105
- userId: 'test-user-id',
106
- phoneNumber: '+1234567890',
107
- isForceRefreshAccountData: false
108
- });
109
-
110
- // Assert
111
- expect(result.successful).toBe(true);
112
- expect(result.contact).toEqual(cachedContact);
113
- // Should not call platform module
114
- expect(connectorRegistry.getConnector).not.toHaveBeenCalled();
115
- });
116
-
117
- test('should bypass cache when isForceRefreshAccountData is true', async () => {
118
- // Arrange
119
- await UserModel.create(mockUser);
120
-
121
- const cachedContact = [
122
- { id: 'contact-1', name: 'Cached Contact', type: 'Contact', phone: '+1234567890' }
123
- ];
124
- await AccountDataModel.create({
125
- rcAccountId: 'rc-account-123',
126
- platformName: 'testCRM',
127
- dataKey: 'contact-+1234567890',
128
- data: cachedContact
129
- });
130
-
131
- const freshContact = [
132
- { id: 'contact-1', name: 'Fresh Contact', type: 'Contact', phone: '+1234567890' }
133
- ];
134
-
135
- const mockConnector = {
136
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
137
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
138
- findContact: jest.fn().mockResolvedValue({
139
- successful: true,
140
- matchedContactInfo: freshContact
141
- })
142
- };
143
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
144
-
145
- // Act
146
- const result = await contactHandler.findContact({
147
- platform: 'testCRM',
148
- userId: 'test-user-id',
149
- phoneNumber: '+1234567890',
150
- isForceRefreshAccountData: true
151
- });
152
-
153
- // Assert
154
- expect(result.successful).toBe(true);
155
- expect(result.contact).toEqual(freshContact);
156
- expect(mockConnector.findContact).toHaveBeenCalled();
157
- });
158
-
159
- test('should find contact with apiKey auth and cache result', async () => {
160
- // Arrange
161
- await UserModel.create(mockUser);
162
-
163
- const matchedContact = [
164
- { id: 'contact-new', name: 'New Contact', type: 'Contact', phone: '+9876543210' }
165
- ];
166
-
167
- const mockConnector = {
168
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
169
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
170
- findContact: jest.fn().mockResolvedValue({
171
- successful: true,
172
- matchedContactInfo: matchedContact
173
- })
174
- };
175
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
176
-
177
- // Act
178
- const result = await contactHandler.findContact({
179
- platform: 'testCRM',
180
- userId: 'test-user-id',
181
- phoneNumber: '+9876543210'
182
- });
183
-
184
- // Assert
185
- expect(result.successful).toBe(true);
186
- expect(result.contact).toEqual(matchedContact);
187
- expect(mockConnector.getBasicAuth).toHaveBeenCalledWith({ apiKey: 'test-access-token' });
188
-
189
- // Verify contact was cached
190
- const cachedData = await AccountDataModel.findOne({
191
- where: {
192
- rcAccountId: 'rc-account-123',
193
- platformName: 'testCRM',
194
- dataKey: 'contact-+9876543210'
195
- }
196
- });
197
- expect(cachedData).not.toBeNull();
198
- expect(cachedData.data).toEqual(matchedContact);
199
- });
200
-
201
- test('should find contact with oauth auth', async () => {
202
- // Arrange
203
- await UserModel.create(mockUser);
204
-
205
- const matchedContact = [
206
- { id: 'oauth-contact', name: 'OAuth Contact', type: 'Lead' }
207
- ];
208
-
209
- const mockConnector = {
210
- getAuthType: jest.fn().mockResolvedValue('oauth'),
211
- getOauthInfo: jest.fn().mockResolvedValue({
212
- clientId: 'client-id',
213
- clientSecret: 'client-secret',
214
- accessTokenUri: 'https://token.url',
215
- authorizationUri: 'https://auth.url'
216
- }),
217
- findContact: jest.fn().mockResolvedValue({
218
- successful: true,
219
- matchedContactInfo: matchedContact
220
- })
221
- };
222
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
223
-
224
- const mockOAuthApp = {};
225
- oauth.getOAuthApp.mockReturnValue(mockOAuthApp);
226
- oauth.checkAndRefreshAccessToken.mockResolvedValue({
227
- ...mockUser,
228
- accessToken: 'refreshed-token'
229
- });
230
-
231
- // Act
232
- const result = await contactHandler.findContact({
233
- platform: 'testCRM',
234
- userId: 'test-user-id',
235
- phoneNumber: '+1111111111'
236
- });
237
-
238
- // Assert
239
- expect(result.successful).toBe(true);
240
- expect(oauth.checkAndRefreshAccessToken).toHaveBeenCalled();
241
- });
242
-
243
- test('should use proxy config when proxyId is present', async () => {
244
- // Arrange
245
- const userWithProxy = {
246
- ...mockUser,
247
- platformAdditionalInfo: { proxyId: 'proxy-123' }
248
- };
249
- await UserModel.create(userWithProxy);
250
-
251
- const proxyConfig = { baseUrl: 'https://proxy.example.com' };
252
- Connector.getProxyConfig.mockResolvedValue(proxyConfig);
253
-
254
- const matchedContact = [{ id: 'proxy-contact', name: 'Proxy Contact' }];
255
-
256
- const mockConnector = {
257
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
258
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
259
- findContact: jest.fn().mockResolvedValue({
260
- successful: true,
261
- matchedContactInfo: matchedContact
262
- })
263
- };
264
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
265
-
266
- // Act
267
- const result = await contactHandler.findContact({
268
- platform: 'testCRM',
269
- userId: 'test-user-id',
270
- phoneNumber: '+2222222222'
271
- });
272
-
273
- // Assert
274
- expect(result.successful).toBe(true);
275
- expect(Connector.getProxyConfig).toHaveBeenCalledWith('proxy-123');
276
- expect(mockConnector.findContact).toHaveBeenCalledWith(
277
- expect.objectContaining({ proxyConfig })
278
- );
279
- });
280
-
281
- test('should return warning when no contacts found', async () => {
282
- // Arrange
283
- await UserModel.create(mockUser);
284
-
285
- const mockConnector = {
286
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
287
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
288
- findContact: jest.fn().mockResolvedValue({
289
- successful: false,
290
- matchedContactInfo: null
291
- })
292
- };
293
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
294
-
295
- // Act
296
- const result = await contactHandler.findContact({
297
- platform: 'testCRM',
298
- userId: 'test-user-id',
299
- phoneNumber: '+9999999999'
300
- });
301
-
302
- // Assert
303
- expect(result.successful).toBe(false);
304
- expect(result.returnMessage.message).toBe('Contact not found');
305
- expect(result.returnMessage.details[0].items[0].text).toContain('+9999999999');
306
- });
307
-
308
- test('should return platform returnMessage when provided', async () => {
309
- // Arrange
310
- await UserModel.create(mockUser);
311
-
312
- const customReturnMessage = {
313
- message: 'Custom platform message',
314
- messageType: 'info',
315
- ttl: 5000
316
- };
317
-
318
- const mockConnector = {
319
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
320
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
321
- findContact: jest.fn().mockResolvedValue({
322
- successful: false,
323
- matchedContactInfo: null,
324
- returnMessage: customReturnMessage
325
- })
326
- };
327
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
328
-
329
- // Act
330
- const result = await contactHandler.findContact({
331
- platform: 'testCRM',
332
- userId: 'test-user-id',
333
- phoneNumber: '+8888888888'
334
- });
335
-
336
- // Assert
337
- expect(result.returnMessage).toEqual(customReturnMessage);
338
- });
339
-
340
- test('should handle 429 rate limit error', async () => {
341
- // Arrange
342
- await UserModel.create(mockUser);
343
-
344
- const mockConnector = {
345
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
346
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
347
- findContact: jest.fn().mockRejectedValue({
348
- response: { status: 429 }
349
- })
350
- };
351
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
352
-
353
- // Act
354
- const result = await contactHandler.findContact({
355
- platform: 'testCRM',
356
- userId: 'test-user-id',
357
- phoneNumber: '+7777777777'
358
- });
359
-
360
- // Assert
361
- expect(result.successful).toBe(false);
362
- expect(result.extraDataTracking.statusCode).toBe(429);
363
- });
364
-
365
- test('should handle 401 authorization error', async () => {
366
- // Arrange
367
- await UserModel.create(mockUser);
368
-
369
- const mockConnector = {
370
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
371
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
372
- findContact: jest.fn().mockRejectedValue({
373
- response: { status: 401 }
374
- })
375
- };
376
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
377
-
378
- // Act
379
- const result = await contactHandler.findContact({
380
- platform: 'testCRM',
381
- userId: 'test-user-id',
382
- phoneNumber: '+6666666666'
383
- });
384
-
385
- // Assert
386
- expect(result.successful).toBe(false);
387
- expect(result.extraDataTracking.statusCode).toBe(401);
388
- });
389
-
390
- test('should update existing cached contact', async () => {
391
- // Arrange
392
- await UserModel.create(mockUser);
393
-
394
- // Create existing cached contact
395
- await AccountDataModel.create({
396
- rcAccountId: 'rc-account-123',
397
- platformName: 'testCRM',
398
- dataKey: 'contact-+5555555555',
399
- data: [{ id: 'old-contact', name: 'Old Name' }]
400
- });
401
-
402
- const updatedContact = [
403
- { id: 'old-contact', name: 'Updated Name', type: 'Contact' }
404
- ];
405
-
406
- const mockConnector = {
407
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
408
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
409
- findContact: jest.fn().mockResolvedValue({
410
- successful: true,
411
- matchedContactInfo: updatedContact
412
- })
413
- };
414
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
415
-
416
- // Act
417
- const result = await contactHandler.findContact({
418
- platform: 'testCRM',
419
- userId: 'test-user-id',
420
- phoneNumber: '+5555555555',
421
- isForceRefreshAccountData: true
422
- });
423
-
424
- // Assert
425
- expect(result.successful).toBe(true);
426
- expect(result.contact).toEqual(updatedContact);
427
-
428
- // Verify cache was updated
429
- const cachedData = await AccountDataModel.findOne({
430
- where: {
431
- rcAccountId: 'rc-account-123',
432
- platformName: 'testCRM',
433
- dataKey: 'contact-+5555555555'
434
- }
435
- });
436
- expect(cachedData.data).toEqual(updatedContact);
437
- });
438
-
439
- test('should remove cached contact when force refresh returns null', async () => {
440
- // Arrange
441
- await UserModel.create(mockUser);
442
- await AccountDataModel.create({
443
- rcAccountId: 'rc-account-123',
444
- platformName: 'testCRM',
445
- dataKey: 'contact-+3333333333',
446
- data: [{ id: 'stale-contact', name: 'Stale Contact' }]
447
- });
448
-
449
- const mockConnector = {
450
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
451
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
452
- findContact: jest.fn().mockResolvedValue({
453
- successful: false,
454
- matchedContactInfo: null
455
- })
456
- };
457
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
458
-
459
- // Act
460
- const result = await contactHandler.findContact({
461
- platform: 'testCRM',
462
- userId: 'test-user-id',
463
- phoneNumber: '+3333333333',
464
- isForceRefreshAccountData: true
465
- });
466
-
467
- // Assert
468
- expect(result.successful).toBe(false);
469
- const cachedData = await AccountDataModel.findOne({
470
- where: {
471
- rcAccountId: 'rc-account-123',
472
- platformName: 'testCRM',
473
- dataKey: 'contact-+3333333333'
474
- }
475
- });
476
- expect(cachedData).toBeNull();
477
- });
478
-
479
- test('should remove cached contact when force refresh returns empty array', async () => {
480
- // Arrange
481
- await UserModel.create(mockUser);
482
- await AccountDataModel.create({
483
- rcAccountId: 'rc-account-123',
484
- platformName: 'testCRM',
485
- dataKey: 'contact-+1212121212',
486
- data: [{ id: 'stale-contact', name: 'Stale Contact' }]
487
- });
488
-
489
- const mockConnector = {
490
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
491
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
492
- findContact: jest.fn().mockResolvedValue({
493
- successful: false,
494
- matchedContactInfo: []
495
- })
496
- };
497
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
498
-
499
- // Act
500
- await contactHandler.findContact({
501
- platform: 'testCRM',
502
- userId: 'test-user-id',
503
- phoneNumber: '+1212121212',
504
- isForceRefreshAccountData: true
505
- });
506
-
507
- // Assert
508
- const cachedData = await AccountDataModel.findOne({
509
- where: {
510
- rcAccountId: 'rc-account-123',
511
- platformName: 'testCRM',
512
- dataKey: 'contact-+1212121212'
513
- }
514
- });
515
- expect(cachedData).toBeNull();
516
- });
517
-
518
- test('should remove cached contact when force refresh returns only new contact placeholder', async () => {
519
- // Arrange
520
- await UserModel.create(mockUser);
521
- await AccountDataModel.create({
522
- rcAccountId: 'rc-account-123',
523
- platformName: 'testCRM',
524
- dataKey: 'contact-+3434343434',
525
- data: [{ id: 'stale-contact', name: 'Stale Contact' }]
526
- });
527
-
528
- const placeholderContact = [
529
- { id: 'new-contact', name: 'Create Contact', isNewContact: true }
530
- ];
531
- const mockConnector = {
532
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
533
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
534
- findContact: jest.fn().mockResolvedValue({
535
- successful: false,
536
- matchedContactInfo: placeholderContact
537
- })
538
- };
539
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
540
-
541
- // Act
542
- const result = await contactHandler.findContact({
543
- platform: 'testCRM',
544
- userId: 'test-user-id',
545
- phoneNumber: '+3434343434',
546
- isForceRefreshAccountData: true
547
- });
548
-
549
- // Assert
550
- expect(result.contact).toEqual(placeholderContact);
551
- const cachedData = await AccountDataModel.findOne({
552
- where: {
553
- rcAccountId: 'rc-account-123',
554
- platformName: 'testCRM',
555
- dataKey: 'contact-+3434343434'
556
- }
557
- });
558
- expect(cachedData).toBeNull();
559
- });
560
-
561
- test('should keep cached contact when force refresh connector call errors', async () => {
562
- // Arrange
563
- await UserModel.create(mockUser);
564
- await AccountDataModel.create({
565
- rcAccountId: 'rc-account-123',
566
- platformName: 'testCRM',
567
- dataKey: 'contact-+5656565656',
568
- data: [{ id: 'stale-contact', name: 'Stale Contact' }]
569
- });
570
-
571
- const mockConnector = {
572
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
573
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
574
- findContact: jest.fn().mockRejectedValue({
575
- response: { status: 500 }
576
- })
577
- };
578
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
579
-
580
- // Act
581
- const result = await contactHandler.findContact({
582
- platform: 'testCRM',
583
- userId: 'test-user-id',
584
- phoneNumber: '+5656565656',
585
- isForceRefreshAccountData: true
586
- });
587
-
588
- // Assert
589
- expect(result.successful).toBe(false);
590
- const cachedData = await AccountDataModel.findOne({
591
- where: {
592
- rcAccountId: 'rc-account-123',
593
- platformName: 'testCRM',
594
- dataKey: 'contact-+5656565656'
595
- }
596
- });
597
- expect(cachedData).not.toBeNull();
598
- expect(cachedData.data).toEqual([{ id: 'stale-contact', name: 'Stale Contact' }]);
599
- });
600
-
601
- test('should work with tracer when provided', async () => {
602
- // Arrange
603
- await UserModel.create(mockUser);
604
-
605
- const mockTracer = {
606
- trace: jest.fn(),
607
- traceError: jest.fn()
608
- };
609
-
610
- const matchedContact = [{ id: 'traced-contact', name: 'Traced Contact' }];
611
-
612
- const mockConnector = {
613
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
614
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
615
- findContact: jest.fn().mockResolvedValue({
616
- successful: true,
617
- matchedContactInfo: matchedContact
618
- })
619
- };
620
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
621
-
622
- // Act
623
- const result = await contactHandler.findContact({
624
- platform: 'testCRM',
625
- userId: 'test-user-id',
626
- phoneNumber: '+4444444444',
627
- tracer: mockTracer
628
- });
629
-
630
- // Assert
631
- expect(result.successful).toBe(true);
632
- expect(mockTracer.trace).toHaveBeenCalled();
633
- });
634
- });
635
-
636
- describe('createContact', () => {
637
- const mockUser = {
638
- id: 'test-user-id',
639
- platform: 'testCRM',
640
- accessToken: 'test-access-token',
641
- platformAdditionalInfo: {}
642
- };
643
-
644
- test('should return error when user not found', async () => {
645
- // Act
646
- const result = await contactHandler.createContact({
647
- platform: 'testCRM',
648
- userId: 'non-existent-user',
649
- phoneNumber: '+1234567890',
650
- newContactName: 'New Contact',
651
- newContactType: 'Contact'
652
- });
653
-
654
- // Assert
655
- expect(result.successful).toBe(false);
656
- expect(result.message).toBe('Contact not found');
657
- });
658
-
659
- test('should return error when user has no access token', async () => {
660
- // Arrange
661
- await UserModel.create({
662
- id: 'test-user-id',
663
- platform: 'testCRM',
664
- accessToken: null
665
- });
666
-
667
- // Act
668
- const result = await contactHandler.createContact({
669
- platform: 'testCRM',
670
- userId: 'test-user-id',
671
- phoneNumber: '+1234567890',
672
- newContactName: 'New Contact',
673
- newContactType: 'Contact'
674
- });
675
-
676
- // Assert
677
- expect(result.successful).toBe(false);
678
- });
679
-
680
- test('should successfully create contact with apiKey auth', async () => {
681
- // Arrange
682
- await UserModel.create(mockUser);
683
-
684
- const createdContact = {
685
- id: 'new-contact-123',
686
- name: 'New Contact',
687
- type: 'Contact',
688
- phone: '+1234567890'
689
- };
690
-
691
- const mockConnector = {
692
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
693
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
694
- createContact: jest.fn().mockResolvedValue({
695
- contactInfo: createdContact,
696
- returnMessage: { message: 'Contact created', messageType: 'success', ttl: 2000 }
697
- })
698
- };
699
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
700
-
701
- // Act
702
- const result = await contactHandler.createContact({
703
- platform: 'testCRM',
704
- userId: 'test-user-id',
705
- phoneNumber: '+1234567890',
706
- newContactName: 'New Contact',
707
- newContactType: 'Contact',
708
- additionalSubmission: {}
709
- });
710
-
711
- // Assert
712
- expect(result.successful).toBe(true);
713
- expect(result.contact).toEqual(createdContact);
714
- expect(mockConnector.createContact).toHaveBeenCalledWith({
715
- user: expect.any(Object),
716
- authHeader: 'Basic base64-encoded',
717
- phoneNumber: '+1234567890',
718
- newContactName: 'New Contact',
719
- newContactType: 'Contact',
720
- additionalSubmission: {},
721
- proxyConfig: null
722
- });
723
- });
724
-
725
- test('should successfully create contact with oauth auth', async () => {
726
- // Arrange
727
- await UserModel.create(mockUser);
728
-
729
- const createdContact = {
730
- id: 'oauth-contact-123',
731
- name: 'OAuth Contact'
732
- };
733
-
734
- const mockConnector = {
735
- getAuthType: jest.fn().mockResolvedValue('oauth'),
736
- getOauthInfo: jest.fn().mockResolvedValue({
737
- clientId: 'client-id',
738
- clientSecret: 'client-secret',
739
- accessTokenUri: 'https://token.url',
740
- authorizationUri: 'https://auth.url'
741
- }),
742
- createContact: jest.fn().mockResolvedValue({
743
- contactInfo: createdContact,
744
- returnMessage: { message: 'Created', messageType: 'success' }
745
- })
746
- };
747
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
748
-
749
- oauth.getOAuthApp.mockReturnValue({});
750
- oauth.checkAndRefreshAccessToken.mockResolvedValue({
751
- ...mockUser,
752
- accessToken: 'refreshed-token'
753
- });
754
-
755
- // Act
756
- const result = await contactHandler.createContact({
757
- platform: 'testCRM',
758
- userId: 'test-user-id',
759
- phoneNumber: '+1234567890',
760
- newContactName: 'OAuth Contact',
761
- newContactType: 'Lead'
762
- });
763
-
764
- // Assert
765
- expect(result.successful).toBe(true);
766
- expect(result.contact).toEqual(createdContact);
767
- expect(oauth.checkAndRefreshAccessToken).toHaveBeenCalled();
768
- });
769
-
770
- test('should return unsuccessful when platform returns null contactInfo', async () => {
771
- // Arrange
772
- await UserModel.create(mockUser);
773
-
774
- const mockConnector = {
775
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
776
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
777
- createContact: jest.fn().mockResolvedValue({
778
- contactInfo: null,
779
- returnMessage: { message: 'Failed to create', messageType: 'error' }
780
- })
781
- };
782
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
783
-
784
- // Act
785
- const result = await contactHandler.createContact({
786
- platform: 'testCRM',
787
- userId: 'test-user-id',
788
- phoneNumber: '+1234567890',
789
- newContactName: 'Failed Contact',
790
- newContactType: 'Contact'
791
- });
792
-
793
- // Assert
794
- expect(result.successful).toBe(false);
795
- expect(result.returnMessage.message).toBe('Failed to create');
796
- });
797
-
798
- test('should handle 429 rate limit error', async () => {
799
- // Arrange
800
- await UserModel.create(mockUser);
801
-
802
- const mockConnector = {
803
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
804
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
805
- createContact: jest.fn().mockRejectedValue({
806
- response: { status: 429 }
807
- })
808
- };
809
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
810
-
811
- // Act
812
- const result = await contactHandler.createContact({
813
- platform: 'testCRM',
814
- userId: 'test-user-id',
815
- phoneNumber: '+1234567890',
816
- newContactName: 'Rate Limited',
817
- newContactType: 'Contact'
818
- });
819
-
820
- // Assert
821
- expect(result.successful).toBe(false);
822
- });
823
-
824
- test('should handle 401 authorization error', async () => {
825
- // Arrange
826
- await UserModel.create(mockUser);
827
-
828
- const mockConnector = {
829
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
830
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
831
- createContact: jest.fn().mockRejectedValue({
832
- response: { status: 401 }
833
- })
834
- };
835
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
836
-
837
- // Act
838
- const result = await contactHandler.createContact({
839
- platform: 'testCRM',
840
- userId: 'test-user-id',
841
- phoneNumber: '+1234567890',
842
- newContactName: 'Unauthorized',
843
- newContactType: 'Contact'
844
- });
845
-
846
- // Assert
847
- expect(result.successful).toBe(false);
848
- expect(result.extraDataTracking.statusCode).toBe(401);
849
- });
850
-
851
- test('should handle generic errors', async () => {
852
- // Arrange
853
- await UserModel.create(mockUser);
854
-
855
- const mockConnector = {
856
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
857
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
858
- createContact: jest.fn().mockRejectedValue(new Error('Unknown error'))
859
- };
860
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
861
-
862
- // Act
863
- const result = await contactHandler.createContact({
864
- platform: 'testCRM',
865
- userId: 'test-user-id',
866
- phoneNumber: '+1234567890',
867
- newContactName: 'Error Contact',
868
- newContactType: 'Contact'
869
- });
870
-
871
- // Assert
872
- expect(result.successful).toBe(false);
873
- expect(result.returnMessage.message).toBe('Error creating contact');
874
- });
875
- });
876
-
877
- describe('findContactWithName', () => {
878
- const mockUser = {
879
- id: 'test-user-id',
880
- platform: 'testCRM',
881
- accessToken: 'test-access-token',
882
- platformAdditionalInfo: {}
883
- };
884
-
885
- test('should return warning when user not found', async () => {
886
- // Act
887
- const result = await contactHandler.findContactWithName({
888
- platform: 'testCRM',
889
- userId: 'non-existent-user',
890
- name: 'John Doe'
891
- });
892
-
893
- // Assert
894
- expect(result.successful).toBe(false);
895
- expect(result.returnMessage.message).toContain('No contact found with name');
896
- });
897
-
898
- test('should find contact by name with apiKey auth', async () => {
899
- // Arrange
900
- await UserModel.create(mockUser);
901
-
902
- const matchedContacts = [
903
- { id: 'contact-1', name: 'John Doe', type: 'Contact' }
904
- ];
905
-
906
- const mockConnector = {
907
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
908
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
909
- findContactWithName: jest.fn().mockResolvedValue({
910
- successful: true,
911
- matchedContactInfo: matchedContacts
912
- })
913
- };
914
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
915
-
916
- // Act
917
- const result = await contactHandler.findContactWithName({
918
- platform: 'testCRM',
919
- userId: 'test-user-id',
920
- name: 'John Doe'
921
- });
922
-
923
- // Assert
924
- expect(result.successful).toBe(true);
925
- expect(result.contact).toEqual(matchedContacts);
926
- });
927
-
928
- test('should return warning when no contacts found by name', async () => {
929
- // Arrange
930
- await UserModel.create(mockUser);
931
-
932
- const mockConnector = {
933
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
934
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
935
- findContactWithName: jest.fn().mockResolvedValue({
936
- successful: false,
937
- matchedContactInfo: null
938
- })
939
- };
940
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
941
-
942
- // Act
943
- const result = await contactHandler.findContactWithName({
944
- platform: 'testCRM',
945
- userId: 'test-user-id',
946
- name: 'Unknown Person'
947
- });
948
-
949
- // Assert
950
- expect(result.successful).toBe(false);
951
- expect(result.returnMessage.message).toContain('No contact found with name');
952
- });
953
-
954
- test('should handle 429 rate limit error', async () => {
955
- // Arrange
956
- await UserModel.create(mockUser);
957
-
958
- const mockConnector = {
959
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
960
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
961
- findContactWithName: jest.fn().mockRejectedValue({
962
- response: { status: 429 }
963
- })
964
- };
965
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
966
-
967
- // Act
968
- const result = await contactHandler.findContactWithName({
969
- platform: 'testCRM',
970
- userId: 'test-user-id',
971
- name: 'Rate Limited'
972
- });
973
-
974
- // Assert
975
- expect(result.successful).toBe(false);
976
- });
977
-
978
- test('should use proxy config when proxyId is present', async () => {
979
- // Arrange
980
- const userWithProxy = {
981
- ...mockUser,
982
- platformAdditionalInfo: { proxyId: 'proxy-123' }
983
- };
984
- await UserModel.create(userWithProxy);
985
-
986
- const proxyConfig = { baseUrl: 'https://proxy.example.com' };
987
- Connector.getProxyConfig.mockResolvedValue(proxyConfig);
988
-
989
- const matchedContacts = [{ id: 'proxy-contact', name: 'Proxy Contact' }];
990
-
991
- const mockConnector = {
992
- getAuthType: jest.fn().mockResolvedValue('apiKey'),
993
- getBasicAuth: jest.fn().mockReturnValue('base64-encoded'),
994
- findContactWithName: jest.fn().mockResolvedValue({
995
- successful: true,
996
- matchedContactInfo: matchedContacts
997
- })
998
- };
999
- connectorRegistry.getConnector.mockReturnValue(mockConnector);
1000
-
1001
- // Act
1002
- const result = await contactHandler.findContactWithName({
1003
- platform: 'testCRM',
1004
- userId: 'test-user-id',
1005
- name: 'Proxy Contact'
1006
- });
1007
-
1008
- // Assert
1009
- expect(result.successful).toBe(true);
1010
- expect(Connector.getProxyConfig).toHaveBeenCalledWith('proxy-123');
1011
- });
1012
- });
1013
- });
1014
-