@onlineapps/conn-orch-api-mapper 1.0.20 → 1.0.22
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/package.json +1 -1
- package/coverage/clover.xml +0 -125
- package/coverage/coverage-final.json +0 -3
- package/coverage/lcov-report/ApiMapper.js.html +0 -1237
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/index.js.html +0 -205
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -256
- package/tests/component/api-mapping-flow.test.js +0 -624
- package/tests/unit/ApiMapper.unit.test.js +0 -599
|
@@ -1,624 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { ApiMapper, create } = require('../../src/index');
|
|
4
|
-
const axios = require('axios');
|
|
5
|
-
|
|
6
|
-
// Mock axios
|
|
7
|
-
jest.mock('axios');
|
|
8
|
-
|
|
9
|
-
describe('API Mapper Component Tests @component', () => {
|
|
10
|
-
let apiMapper;
|
|
11
|
-
let mockOpenApiSpec;
|
|
12
|
-
let mockLogger;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
jest.clearAllMocks();
|
|
16
|
-
|
|
17
|
-
// Mock logger
|
|
18
|
-
mockLogger = {
|
|
19
|
-
info: jest.fn(),
|
|
20
|
-
error: jest.fn(),
|
|
21
|
-
debug: jest.fn(),
|
|
22
|
-
warn: jest.fn()
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Sample OpenAPI spec
|
|
26
|
-
mockOpenApiSpec = {
|
|
27
|
-
openapi: '3.0.0',
|
|
28
|
-
info: {
|
|
29
|
-
title: 'Test API',
|
|
30
|
-
version: '1.0.0'
|
|
31
|
-
},
|
|
32
|
-
servers: [
|
|
33
|
-
{ url: 'http://localhost:3000' }
|
|
34
|
-
],
|
|
35
|
-
paths: {
|
|
36
|
-
'/users': {
|
|
37
|
-
get: {
|
|
38
|
-
operationId: 'listUsers',
|
|
39
|
-
summary: 'List all users',
|
|
40
|
-
parameters: [
|
|
41
|
-
{
|
|
42
|
-
name: 'limit',
|
|
43
|
-
in: 'query',
|
|
44
|
-
schema: { type: 'integer' }
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
name: 'offset',
|
|
48
|
-
in: 'query',
|
|
49
|
-
schema: { type: 'integer' }
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
responses: {
|
|
53
|
-
'200': {
|
|
54
|
-
description: 'User list',
|
|
55
|
-
content: {
|
|
56
|
-
'application/json': {
|
|
57
|
-
schema: {
|
|
58
|
-
type: 'array',
|
|
59
|
-
items: { $ref: '#/components/schemas/User' }
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
post: {
|
|
67
|
-
operationId: 'createUser',
|
|
68
|
-
summary: 'Create a new user',
|
|
69
|
-
requestBody: {
|
|
70
|
-
required: true,
|
|
71
|
-
content: {
|
|
72
|
-
'application/json': {
|
|
73
|
-
schema: { $ref: '#/components/schemas/User' }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
responses: {
|
|
78
|
-
'201': {
|
|
79
|
-
description: 'User created',
|
|
80
|
-
content: {
|
|
81
|
-
'application/json': {
|
|
82
|
-
schema: { $ref: '#/components/schemas/User' }
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
'/users/{userId}': {
|
|
90
|
-
get: {
|
|
91
|
-
operationId: 'getUser',
|
|
92
|
-
summary: 'Get user by ID',
|
|
93
|
-
parameters: [
|
|
94
|
-
{
|
|
95
|
-
name: 'userId',
|
|
96
|
-
in: 'path',
|
|
97
|
-
required: true,
|
|
98
|
-
schema: { type: 'string' }
|
|
99
|
-
}
|
|
100
|
-
],
|
|
101
|
-
responses: {
|
|
102
|
-
'200': {
|
|
103
|
-
description: 'User details',
|
|
104
|
-
content: {
|
|
105
|
-
'application/json': {
|
|
106
|
-
schema: { $ref: '#/components/schemas/User' }
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
'404': {
|
|
111
|
-
description: 'User not found'
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
put: {
|
|
116
|
-
operationId: 'updateUser',
|
|
117
|
-
summary: 'Update user',
|
|
118
|
-
parameters: [
|
|
119
|
-
{
|
|
120
|
-
name: 'userId',
|
|
121
|
-
in: 'path',
|
|
122
|
-
required: true,
|
|
123
|
-
schema: { type: 'string' }
|
|
124
|
-
}
|
|
125
|
-
],
|
|
126
|
-
requestBody: {
|
|
127
|
-
required: true,
|
|
128
|
-
content: {
|
|
129
|
-
'application/json': {
|
|
130
|
-
schema: { $ref: '#/components/schemas/User' }
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
responses: {
|
|
135
|
-
'200': {
|
|
136
|
-
description: 'User updated'
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
delete: {
|
|
141
|
-
operationId: 'deleteUser',
|
|
142
|
-
summary: 'Delete user',
|
|
143
|
-
parameters: [
|
|
144
|
-
{
|
|
145
|
-
name: 'userId',
|
|
146
|
-
in: 'path',
|
|
147
|
-
required: true,
|
|
148
|
-
schema: { type: 'string' }
|
|
149
|
-
}
|
|
150
|
-
],
|
|
151
|
-
responses: {
|
|
152
|
-
'204': {
|
|
153
|
-
description: 'User deleted'
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
},
|
|
158
|
-
'/auth/login': {
|
|
159
|
-
post: {
|
|
160
|
-
operationId: 'login',
|
|
161
|
-
summary: 'User login',
|
|
162
|
-
requestBody: {
|
|
163
|
-
required: true,
|
|
164
|
-
content: {
|
|
165
|
-
'application/json': {
|
|
166
|
-
schema: {
|
|
167
|
-
type: 'object',
|
|
168
|
-
properties: {
|
|
169
|
-
username: { type: 'string' },
|
|
170
|
-
password: { type: 'string' }
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
responses: {
|
|
177
|
-
'200': {
|
|
178
|
-
description: 'Login successful',
|
|
179
|
-
content: {
|
|
180
|
-
'application/json': {
|
|
181
|
-
schema: {
|
|
182
|
-
type: 'object',
|
|
183
|
-
properties: {
|
|
184
|
-
token: { type: 'string' },
|
|
185
|
-
user: { $ref: '#/components/schemas/User' }
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
components: {
|
|
196
|
-
schemas: {
|
|
197
|
-
User: {
|
|
198
|
-
type: 'object',
|
|
199
|
-
properties: {
|
|
200
|
-
id: { type: 'string' },
|
|
201
|
-
name: { type: 'string' },
|
|
202
|
-
email: { type: 'string' },
|
|
203
|
-
role: { type: 'string' }
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
apiMapper = new ApiMapper({
|
|
211
|
-
openApiSpec: mockOpenApiSpec,
|
|
212
|
-
serviceUrl: 'http://test-service:3000',
|
|
213
|
-
logger: mockLogger
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
describe('Complete Mapping Flow', () => {
|
|
218
|
-
it('should map and execute GET request with query parameters', async () => {
|
|
219
|
-
const mockResponse = {
|
|
220
|
-
data: [
|
|
221
|
-
{ id: '1', name: 'John', email: 'john@example.com' },
|
|
222
|
-
{ id: '2', name: 'Jane', email: 'jane@example.com' }
|
|
223
|
-
],
|
|
224
|
-
status: 200,
|
|
225
|
-
headers: { 'content-type': 'application/json' }
|
|
226
|
-
};
|
|
227
|
-
axios.mockResolvedValue(mockResponse);
|
|
228
|
-
|
|
229
|
-
const params = {
|
|
230
|
-
limit: 10,
|
|
231
|
-
offset: 0
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const result = await apiMapper.callOperation('listUsers', params);
|
|
235
|
-
|
|
236
|
-
expect(axios).toHaveBeenCalledWith({
|
|
237
|
-
method: 'GET',
|
|
238
|
-
url: 'http://test-service:3000/users',
|
|
239
|
-
params: {
|
|
240
|
-
limit: 10,
|
|
241
|
-
offset: 0
|
|
242
|
-
},
|
|
243
|
-
headers: {},
|
|
244
|
-
data: null
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
expect(result).toEqual(mockResponse.data);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it('should map and execute POST request with body', async () => {
|
|
251
|
-
const mockResponse = {
|
|
252
|
-
data: { id: '3', name: 'Bob', email: 'bob@example.com', role: 'user' },
|
|
253
|
-
status: 201,
|
|
254
|
-
headers: { 'content-type': 'application/json' }
|
|
255
|
-
};
|
|
256
|
-
axios.mockResolvedValue(mockResponse);
|
|
257
|
-
|
|
258
|
-
const params = {
|
|
259
|
-
body: {
|
|
260
|
-
name: 'Bob',
|
|
261
|
-
email: 'bob@example.com',
|
|
262
|
-
role: 'user'
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
const result = await apiMapper.callOperation('createUser', params);
|
|
267
|
-
|
|
268
|
-
expect(axios).toHaveBeenCalledWith({
|
|
269
|
-
method: 'POST',
|
|
270
|
-
url: 'http://test-service:3000/users',
|
|
271
|
-
params: {},
|
|
272
|
-
headers: { 'Content-Type': 'application/json' },
|
|
273
|
-
data: params.body
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
expect(result).toEqual(mockResponse.data);
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it('should map and execute request with path parameters', async () => {
|
|
280
|
-
const mockResponse = {
|
|
281
|
-
data: { id: '123', name: 'Alice', email: 'alice@example.com' },
|
|
282
|
-
status: 200
|
|
283
|
-
};
|
|
284
|
-
axios.mockResolvedValue(mockResponse);
|
|
285
|
-
|
|
286
|
-
const params = {
|
|
287
|
-
userId: '123'
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const result = await apiMapper.callOperation('getUser', params);
|
|
291
|
-
|
|
292
|
-
expect(axios).toHaveBeenCalledWith({
|
|
293
|
-
method: 'GET',
|
|
294
|
-
url: 'http://test-service:3000/users/123',
|
|
295
|
-
params: {},
|
|
296
|
-
headers: {},
|
|
297
|
-
data: null
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
expect(result).toEqual(mockResponse.data);
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it('should handle mixed parameters (path, query, body)', async () => {
|
|
304
|
-
// Add a complex endpoint to the spec
|
|
305
|
-
apiMapper.operations['complexOperation'] = {
|
|
306
|
-
method: 'POST',
|
|
307
|
-
path: '/api/v1/organizations/{orgId}/users/{userId}/actions',
|
|
308
|
-
parameters: [
|
|
309
|
-
{ name: 'orgId', in: 'path', required: true },
|
|
310
|
-
{ name: 'userId', in: 'path', required: true },
|
|
311
|
-
{ name: 'action', in: 'query' },
|
|
312
|
-
{ name: 'notify', in: 'query' }
|
|
313
|
-
],
|
|
314
|
-
requestBody: {
|
|
315
|
-
content: {
|
|
316
|
-
'application/json': {
|
|
317
|
-
schema: { type: 'object' }
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
const mockResponse = { data: { success: true }, status: 200 };
|
|
324
|
-
axios.mockResolvedValue(mockResponse);
|
|
325
|
-
|
|
326
|
-
const timestamp = Date.now();
|
|
327
|
-
const params = {
|
|
328
|
-
orgId: 'org-123',
|
|
329
|
-
userId: 'user-456',
|
|
330
|
-
action: 'activate',
|
|
331
|
-
notify: true,
|
|
332
|
-
body: { metadata: { timestamp } }
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
await apiMapper.callOperation('complexOperation', params);
|
|
336
|
-
|
|
337
|
-
expect(axios).toHaveBeenCalledWith({
|
|
338
|
-
method: 'POST',
|
|
339
|
-
url: 'http://test-service:3000/api/v1/organizations/org-123/users/user-456/actions',
|
|
340
|
-
params: {
|
|
341
|
-
action: 'activate',
|
|
342
|
-
notify: true
|
|
343
|
-
},
|
|
344
|
-
headers: { 'Content-Type': 'application/json' },
|
|
345
|
-
data: { metadata: { timestamp } }
|
|
346
|
-
});
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe('Error Handling', () => {
|
|
351
|
-
it('should handle 404 errors appropriately', async () => {
|
|
352
|
-
const error = {
|
|
353
|
-
response: {
|
|
354
|
-
status: 404,
|
|
355
|
-
data: { error: 'User not found' }
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
axios.mockRejectedValue(error);
|
|
359
|
-
|
|
360
|
-
await expect(apiMapper.callOperation('getUser', { userId: 'nonexistent' }))
|
|
361
|
-
.rejects.toThrow();
|
|
362
|
-
|
|
363
|
-
expect(mockLogger.error).toHaveBeenCalled();
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
it('should handle network errors', async () => {
|
|
367
|
-
const error = new Error('Network error');
|
|
368
|
-
error.code = 'ECONNREFUSED';
|
|
369
|
-
axios.mockRejectedValue(error);
|
|
370
|
-
|
|
371
|
-
await expect(apiMapper.callOperation('listUsers', {}))
|
|
372
|
-
.rejects.toThrow('Network error');
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it('should handle malformed responses', async () => {
|
|
376
|
-
axios.mockResolvedValue({
|
|
377
|
-
data: 'Invalid JSON response',
|
|
378
|
-
status: 200
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
const result = await apiMapper.callOperation('listUsers', {});
|
|
382
|
-
expect(result).toBe('Invalid JSON response');
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
it('should throw error for unknown operations', () => {
|
|
386
|
-
expect(() => apiMapper.mapOperationToEndpoint('unknownOperation'))
|
|
387
|
-
.toThrow('Operation not found: unknownOperation');
|
|
388
|
-
});
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
describe('Request Transformation', () => {
|
|
392
|
-
it('should correctly transform parameters based on OpenAPI spec', () => {
|
|
393
|
-
const operation = apiMapper.operations['getUser'];
|
|
394
|
-
const cookbookParams = {
|
|
395
|
-
userId: '123',
|
|
396
|
-
extraParam: 'should-be-ignored'
|
|
397
|
-
};
|
|
398
|
-
|
|
399
|
-
const transformed = apiMapper.transformRequest(cookbookParams, operation.parameters || []);
|
|
400
|
-
|
|
401
|
-
expect(transformed.params.userId).toBe('123');
|
|
402
|
-
expect(transformed.params.extraParam).toBeUndefined();
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
it('should handle optional parameters', () => {
|
|
406
|
-
const operation = apiMapper.operations['listUsers'];
|
|
407
|
-
const cookbookParams = {
|
|
408
|
-
limit: 5
|
|
409
|
-
// offset is omitted
|
|
410
|
-
};
|
|
411
|
-
|
|
412
|
-
const transformed = apiMapper.transformRequest(cookbookParams, operation.parameters || []);
|
|
413
|
-
|
|
414
|
-
expect(transformed.query.limit).toBe(5);
|
|
415
|
-
expect(transformed.query.offset).toBeUndefined();
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
it('should separate body from other parameters', () => {
|
|
419
|
-
const operation = apiMapper.operations['updateUser'];
|
|
420
|
-
const cookbookParams = {
|
|
421
|
-
userId: '123',
|
|
422
|
-
body: {
|
|
423
|
-
name: 'Updated Name',
|
|
424
|
-
email: 'updated@example.com'
|
|
425
|
-
}
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
const transformed = apiMapper.transformRequest(cookbookParams, operation.parameters || []);
|
|
429
|
-
|
|
430
|
-
expect(transformed.params.userId).toBe('123');
|
|
431
|
-
expect(transformed.body).toEqual({
|
|
432
|
-
name: 'Updated Name',
|
|
433
|
-
email: 'updated@example.com'
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
describe('Direct Call Mode', () => {
|
|
439
|
-
it('should use Express app for direct calls when configured', async () => {
|
|
440
|
-
const mockApp = {
|
|
441
|
-
_router: {
|
|
442
|
-
stack: []
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
const mockReq = {};
|
|
447
|
-
const mockRes = {
|
|
448
|
-
status: jest.fn().mockReturnThis(),
|
|
449
|
-
json: jest.fn(),
|
|
450
|
-
send: jest.fn()
|
|
451
|
-
};
|
|
452
|
-
|
|
453
|
-
const directMapper = new ApiMapper({
|
|
454
|
-
openApiSpec: mockOpenApiSpec,
|
|
455
|
-
service: mockApp,
|
|
456
|
-
directCall: true,
|
|
457
|
-
logger: mockLogger
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
// Mock _callDirectly method
|
|
461
|
-
directMapper._callDirectly = jest.fn().mockResolvedValue({
|
|
462
|
-
data: { id: '1' },
|
|
463
|
-
status: 200
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
const result = await directMapper.callOperation('getUser', { userId: '1' });
|
|
467
|
-
|
|
468
|
-
expect(directMapper._callDirectly).toHaveBeenCalled();
|
|
469
|
-
expect(result).toEqual({ id: '1' });
|
|
470
|
-
});
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
describe('OpenAPI Parsing', () => {
|
|
474
|
-
it('should parse all operations from OpenAPI spec', () => {
|
|
475
|
-
const operations = apiMapper.operations;
|
|
476
|
-
|
|
477
|
-
expect(operations).toHaveProperty('listUsers');
|
|
478
|
-
expect(operations).toHaveProperty('createUser');
|
|
479
|
-
expect(operations).toHaveProperty('getUser');
|
|
480
|
-
expect(operations).toHaveProperty('updateUser');
|
|
481
|
-
expect(operations).toHaveProperty('deleteUser');
|
|
482
|
-
expect(operations).toHaveProperty('login');
|
|
483
|
-
|
|
484
|
-
expect(operations.listUsers.method).toBe('GET');
|
|
485
|
-
expect(operations.listUsers.path).toBe('/users');
|
|
486
|
-
expect(operations.createUser.method).toBe('POST');
|
|
487
|
-
expect(operations.createUser.path).toBe('/users');
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
it('should handle spec without operationId', () => {
|
|
491
|
-
const specWithoutOperationId = {
|
|
492
|
-
...mockOpenApiSpec,
|
|
493
|
-
paths: {
|
|
494
|
-
'/test': {
|
|
495
|
-
get: {
|
|
496
|
-
summary: 'Test endpoint'
|
|
497
|
-
// No operationId
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
const mapper = new ApiMapper({
|
|
504
|
-
openApiSpec: specWithoutOperationId,
|
|
505
|
-
logger: mockLogger
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
// Should generate operationId from method and path
|
|
509
|
-
expect(mapper.operations).toHaveProperty('get__test');
|
|
510
|
-
});
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
describe('Response Transformation', () => {
|
|
514
|
-
it('should extract data from successful responses', async () => {
|
|
515
|
-
const response = {
|
|
516
|
-
data: { id: '1', name: 'John' },
|
|
517
|
-
status: 200,
|
|
518
|
-
headers: { 'content-type': 'application/json' }
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
const transformed = await apiMapper.transformResponse(response);
|
|
522
|
-
expect(transformed).toEqual({ id: '1', name: 'John' });
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
it('should handle empty responses', async () => {
|
|
526
|
-
const response = {
|
|
527
|
-
data: null,
|
|
528
|
-
status: 204
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
const transformed = await apiMapper.transformResponse(response);
|
|
532
|
-
expect(transformed).toEqual(response);
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
it('should preserve error responses', async () => {
|
|
536
|
-
const response = {
|
|
537
|
-
data: { error: 'Bad request', details: 'Invalid email' },
|
|
538
|
-
status: 400
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
const transformed = await apiMapper.transformResponse(response);
|
|
542
|
-
expect(transformed).toEqual({ error: 'Bad request', details: 'Invalid email' });
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
describe('Factory Function', () => {
|
|
547
|
-
it('should create ApiMapper instance using factory', () => {
|
|
548
|
-
const mapper = create({
|
|
549
|
-
openApiSpec: mockOpenApiSpec,
|
|
550
|
-
serviceUrl: 'http://factory-test:3000'
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
expect(mapper).toBeInstanceOf(ApiMapper);
|
|
554
|
-
expect(mapper.serviceUrl).toBe('http://factory-test:3000');
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
it('should throw error when spec is missing', () => {
|
|
558
|
-
expect(() => create({}))
|
|
559
|
-
.toThrow('OpenAPI specification is required');
|
|
560
|
-
});
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
describe('Spec Reloading', () => {
|
|
564
|
-
it('should reload OpenAPI spec dynamically', () => {
|
|
565
|
-
const newSpec = {
|
|
566
|
-
...mockOpenApiSpec,
|
|
567
|
-
paths: {
|
|
568
|
-
'/new-endpoint': {
|
|
569
|
-
get: {
|
|
570
|
-
operationId: 'newOperation',
|
|
571
|
-
summary: 'New endpoint'
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
apiMapper.loadOpenApiSpec(newSpec);
|
|
578
|
-
|
|
579
|
-
expect(apiMapper.operations).toHaveProperty('newOperation');
|
|
580
|
-
expect(apiMapper.operations.newOperation.path).toBe('/new-endpoint');
|
|
581
|
-
});
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
describe('Variable Resolution', () => {
|
|
585
|
-
it('should resolve cookbook variables in parameters', () => {
|
|
586
|
-
// Check if resolveVariables method exists
|
|
587
|
-
if (!apiMapper._resolveVariables && !apiMapper.resolveVariables) {
|
|
588
|
-
// Skip test if method doesn't exist
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
const params = {
|
|
592
|
-
userId: '${context.user.id}',
|
|
593
|
-
name: '${input.userName}'
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
const context = {
|
|
597
|
-
user: { id: '123' }
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
const input = {
|
|
601
|
-
userName: 'John Doe'
|
|
602
|
-
};
|
|
603
|
-
|
|
604
|
-
const resolved = apiMapper._resolveVariables ?
|
|
605
|
-
apiMapper._resolveVariables(params, { context, input }) :
|
|
606
|
-
apiMapper.resolveVariables(params, { context, input });
|
|
607
|
-
|
|
608
|
-
expect(resolved.userId).toBe('123');
|
|
609
|
-
expect(resolved.name).toBe('John Doe');
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
it('should handle missing variables gracefully', () => {
|
|
613
|
-
const params = {
|
|
614
|
-
userId: '${context.user.id}',
|
|
615
|
-
name: 'static-value'
|
|
616
|
-
};
|
|
617
|
-
|
|
618
|
-
const resolved = apiMapper._resolveVariables(params, {});
|
|
619
|
-
|
|
620
|
-
expect(resolved.userId).toBeUndefined();
|
|
621
|
-
expect(resolved.name).toBe('static-value');
|
|
622
|
-
});
|
|
623
|
-
});
|
|
624
|
-
});
|