@app-connect/core 1.7.11 → 1.7.15

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,281 @@
1
+ const getGoogleFilePicker = require('../../../mcp/tools/getGoogleFilePicker');
2
+ const jwt = require('../../../lib/jwt');
3
+ const { UserModel } = require('../../../models/userModel');
4
+ const axios = require('axios');
5
+
6
+ // Mock dependencies
7
+ jest.mock('../../../lib/jwt');
8
+ jest.mock('../../../models/userModel');
9
+ jest.mock('axios');
10
+
11
+ describe('MCP Tool: getGoogleFilePicker', () => {
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+ process.env.APP_SERVER = 'https://test-app-server.com';
15
+ });
16
+
17
+ describe('tool definition', () => {
18
+ test('should have correct tool definition', () => {
19
+ expect(getGoogleFilePicker.definition).toBeDefined();
20
+ expect(getGoogleFilePicker.definition.name).toBe('getGoogleFilePicker');
21
+ expect(getGoogleFilePicker.definition.description).toContain('REQUIRES AUTHENTICATION');
22
+ expect(getGoogleFilePicker.definition.description).toContain('Google Sheets file picker');
23
+ expect(getGoogleFilePicker.definition.inputSchema).toBeDefined();
24
+ });
25
+
26
+ test('should require jwtToken parameter', () => {
27
+ expect(getGoogleFilePicker.definition.inputSchema.required).toContain('jwtToken');
28
+ });
29
+
30
+ test('should have optional sheetName parameter', () => {
31
+ expect(getGoogleFilePicker.definition.inputSchema.properties).toHaveProperty('sheetName');
32
+ expect(getGoogleFilePicker.definition.inputSchema.required).not.toContain('sheetName');
33
+ });
34
+
35
+ test('should have correct annotations', () => {
36
+ expect(getGoogleFilePicker.definition.annotations).toEqual({
37
+ readOnlyHint: false,
38
+ openWorldHint: true,
39
+ destructiveHint: false
40
+ });
41
+ });
42
+ });
43
+
44
+ describe('execute - file picker URL', () => {
45
+ test('should return file picker URL successfully', async () => {
46
+ // Arrange
47
+ jwt.decodeJwt.mockReturnValue({
48
+ id: 'user-123'
49
+ });
50
+
51
+ UserModel.findByPk.mockResolvedValue({
52
+ id: 'user-123',
53
+ name: 'Test User'
54
+ });
55
+
56
+ // Act
57
+ const result = await getGoogleFilePicker.execute({
58
+ jwtToken: 'mock-jwt-token'
59
+ });
60
+
61
+ // Assert
62
+ expect(result).toEqual({
63
+ success: true,
64
+ data: {
65
+ filePickerUrl: 'https://test-app-server.com/googleSheets/filePicker?token=mock-jwt-token}',
66
+ message: expect.stringContaining('Please open this URL')
67
+ }
68
+ });
69
+ expect(jwt.decodeJwt).toHaveBeenCalledWith('mock-jwt-token');
70
+ expect(UserModel.findByPk).toHaveBeenCalledWith('user-123');
71
+ });
72
+ });
73
+
74
+ describe('execute - create new sheet', () => {
75
+ test('should create new sheet when sheetName is provided', async () => {
76
+ // Arrange
77
+ jwt.decodeJwt.mockReturnValue({
78
+ id: 'user-123'
79
+ });
80
+
81
+ UserModel.findByPk.mockResolvedValue({
82
+ id: 'user-123',
83
+ name: 'Test User'
84
+ });
85
+
86
+ const mockSheetResponse = {
87
+ data: {
88
+ success: true,
89
+ data: {
90
+ sheetId: 'sheet-123',
91
+ sheetName: 'My Call Logs'
92
+ }
93
+ }
94
+ };
95
+
96
+ axios.post.mockResolvedValue(mockSheetResponse);
97
+
98
+ // Act
99
+ const result = await getGoogleFilePicker.execute({
100
+ jwtToken: 'mock-jwt-token',
101
+ sheetName: 'My Call Logs'
102
+ });
103
+
104
+ // Assert
105
+ expect(result).toEqual({
106
+ success: true,
107
+ data: {
108
+ sheetId: 'sheet-123',
109
+ sheetName: 'My Call Logs'
110
+ }
111
+ });
112
+ expect(axios.post).toHaveBeenCalledWith(
113
+ 'https://test-app-server.com/googleSheets/sheet?jwtToken=mock-jwt-token',
114
+ { name: 'My Call Logs' }
115
+ );
116
+ });
117
+
118
+ test('should return error when sheet creation fails', async () => {
119
+ // Arrange
120
+ jwt.decodeJwt.mockReturnValue({
121
+ id: 'user-123'
122
+ });
123
+
124
+ UserModel.findByPk.mockResolvedValue({
125
+ id: 'user-123',
126
+ name: 'Test User'
127
+ });
128
+
129
+ axios.post.mockRejectedValue(new Error('Failed to create sheet'));
130
+
131
+ // Act
132
+ const result = await getGoogleFilePicker.execute({
133
+ jwtToken: 'mock-jwt-token',
134
+ sheetName: 'My Call Logs'
135
+ });
136
+
137
+ // Assert
138
+ expect(result.success).toBe(false);
139
+ expect(result.error).toBe('Failed to create sheet');
140
+ expect(result.errorDetails).toBeDefined();
141
+ });
142
+ });
143
+
144
+ describe('execute - error handling', () => {
145
+ test('should return error when jwtToken is missing', async () => {
146
+ // Act
147
+ const result = await getGoogleFilePicker.execute({});
148
+
149
+ // Assert
150
+ expect(result).toEqual({
151
+ success: false,
152
+ error: 'JWT token is required. Please authenticate with googleSheets platform first using the doAuth tool.'
153
+ });
154
+ });
155
+
156
+ test('should return error when jwtToken is null', async () => {
157
+ // Act
158
+ const result = await getGoogleFilePicker.execute({
159
+ jwtToken: null
160
+ });
161
+
162
+ // Assert
163
+ expect(result).toEqual({
164
+ success: false,
165
+ error: 'JWT token is required. Please authenticate with googleSheets platform first using the doAuth tool.'
166
+ });
167
+ });
168
+
169
+ test('should return error when JWT is invalid (no userId)', async () => {
170
+ // Arrange
171
+ jwt.decodeJwt.mockReturnValue({
172
+ // id is missing
173
+ platform: 'googleSheets'
174
+ });
175
+
176
+ // Act
177
+ const result = await getGoogleFilePicker.execute({
178
+ jwtToken: 'invalid-jwt-token'
179
+ });
180
+
181
+ // Assert
182
+ expect(result).toEqual({
183
+ success: false,
184
+ error: 'Invalid JWT token: userId not found'
185
+ });
186
+ });
187
+
188
+ test('should return error when JWT decode returns null', async () => {
189
+ // Arrange
190
+ jwt.decodeJwt.mockReturnValue(null);
191
+
192
+ // Act
193
+ const result = await getGoogleFilePicker.execute({
194
+ jwtToken: 'malformed-jwt-token'
195
+ });
196
+
197
+ // Assert
198
+ expect(result).toEqual({
199
+ success: false,
200
+ error: 'Invalid JWT token: userId not found'
201
+ });
202
+ });
203
+
204
+ test('should return error when user not found', async () => {
205
+ // Arrange
206
+ jwt.decodeJwt.mockReturnValue({
207
+ id: 'nonexistent-user'
208
+ });
209
+
210
+ UserModel.findByPk.mockResolvedValue(null);
211
+
212
+ // Act
213
+ const result = await getGoogleFilePicker.execute({
214
+ jwtToken: 'mock-jwt-token'
215
+ });
216
+
217
+ // Assert
218
+ expect(result).toEqual({
219
+ success: false,
220
+ error: 'User not found. Please authenticate with googleSheets platform first.'
221
+ });
222
+ expect(UserModel.findByPk).toHaveBeenCalledWith('nonexistent-user');
223
+ });
224
+
225
+ test('should handle database errors gracefully', async () => {
226
+ // Arrange
227
+ jwt.decodeJwt.mockReturnValue({
228
+ id: 'user-123'
229
+ });
230
+
231
+ UserModel.findByPk.mockRejectedValue(new Error('Database connection failed'));
232
+
233
+ // Act
234
+ const result = await getGoogleFilePicker.execute({
235
+ jwtToken: 'mock-jwt-token'
236
+ });
237
+
238
+ // Assert
239
+ expect(result.success).toBe(false);
240
+ expect(result.error).toBe('Database connection failed');
241
+ expect(result.errorDetails).toBeDefined();
242
+ });
243
+
244
+ test('should handle JWT decode errors gracefully', async () => {
245
+ // Arrange
246
+ jwt.decodeJwt.mockImplementation(() => {
247
+ throw new Error('JWT decode error');
248
+ });
249
+
250
+ // Act
251
+ const result = await getGoogleFilePicker.execute({
252
+ jwtToken: 'corrupted-jwt-token'
253
+ });
254
+
255
+ // Assert
256
+ expect(result.success).toBe(false);
257
+ expect(result.error).toBe('JWT decode error');
258
+ expect(result.errorDetails).toBeDefined();
259
+ });
260
+
261
+ test('should handle errors without message property', async () => {
262
+ // Arrange
263
+ jwt.decodeJwt.mockReturnValue({
264
+ id: 'user-123'
265
+ });
266
+
267
+ const errorWithoutMessage = { code: 'UNKNOWN_ERROR' };
268
+ UserModel.findByPk.mockRejectedValue(errorWithoutMessage);
269
+
270
+ // Act
271
+ const result = await getGoogleFilePicker.execute({
272
+ jwtToken: 'mock-jwt-token'
273
+ });
274
+
275
+ // Assert
276
+ expect(result.success).toBe(false);
277
+ expect(result.error).toBe('Unknown error occurred');
278
+ });
279
+ });
280
+ });
281
+
@@ -26,10 +26,10 @@ describe('MCP Tool: getPublicConnectors', () => {
26
26
 
27
27
  describe('execute', () => {
28
28
  test('should return public connectors successfully', async () => {
29
- // Arrange
29
+ // Arrange - use supported platform names: 'googleSheets' and 'clio'
30
30
  const mockConnectors = [
31
- { id: '1', name: 'salesforce', displayName: 'Salesforce' },
32
- { id: '2', name: 'hubspot', displayName: 'HubSpot' }
31
+ { id: '1', name: 'googleSheets', displayName: 'Google Sheets' },
32
+ { id: '2', name: 'clio', displayName: 'Clio' }
33
33
  ];
34
34
 
35
35
  developerPortal.getPublicConnectorList.mockResolvedValue({
@@ -42,20 +42,20 @@ describe('MCP Tool: getPublicConnectors', () => {
42
42
  // Assert
43
43
  expect(result).toEqual({
44
44
  success: true,
45
- data: ['Salesforce', 'HubSpot']
45
+ data: ['Google Sheets', 'Clio']
46
46
  });
47
47
  expect(developerPortal.getPublicConnectorList).toHaveBeenCalledTimes(1);
48
48
  });
49
49
 
50
50
  test('should include private connectors when RC_ACCOUNT_ID is set', async () => {
51
- // Arrange
51
+ // Arrange - use supported platform names
52
52
  process.env.RC_ACCOUNT_ID = 'test-account-id';
53
53
 
54
54
  const mockPublicConnectors = [
55
- { id: '1', name: 'salesforce', displayName: 'Salesforce' }
55
+ { id: '1', name: 'googleSheets', displayName: 'Google Sheets' }
56
56
  ];
57
57
  const mockPrivateConnectors = [
58
- { id: '3', name: 'custom-crm', displayName: 'Custom CRM' }
58
+ { id: '3', name: 'clio', displayName: 'Clio' }
59
59
  ];
60
60
 
61
61
  developerPortal.getPublicConnectorList.mockResolvedValue({
@@ -71,7 +71,7 @@ describe('MCP Tool: getPublicConnectors', () => {
71
71
  // Assert
72
72
  expect(result).toEqual({
73
73
  success: true,
74
- data: ['Salesforce', 'Custom CRM']
74
+ data: ['Google Sheets', 'Clio']
75
75
  });
76
76
  expect(developerPortal.getPublicConnectorList).toHaveBeenCalledTimes(1);
77
77
  expect(developerPortal.getPrivateConnectorList).toHaveBeenCalledTimes(1);