@forge/teamwork-graph 1.2.0-next.3-experimental-255e232 → 1.2.0-next.5
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/out/__test__/entity-operations.test.js +82 -5
- package/out/__test__/graph-extended.test.js +52 -28
- package/out/__test__/group-operations.test.js +3 -2
- package/out/__test__/user-operations.test.js +5 -4
- package/out/__test__/validators.test.d.ts +2 -0
- package/out/__test__/validators.test.d.ts.map +1 -0
- package/out/__test__/validators.test.js +329 -0
- package/out/graph.d.ts +3 -6
- package/out/graph.d.ts.map +1 -1
- package/out/graph.js +51 -116
- package/out/types/common.d.ts +0 -21
- package/out/types/common.d.ts.map +1 -1
- package/out/types/entities/branch.d.ts +14 -0
- package/out/types/entities/branch.d.ts.map +1 -0
- package/out/types/entities/branch.js +2 -0
- package/out/types/entities/commit.d.ts +26 -0
- package/out/types/entities/commit.d.ts.map +1 -0
- package/out/types/entities/commit.js +2 -0
- package/out/types/entities/index.d.ts +4 -2
- package/out/types/entities/index.d.ts.map +1 -1
- package/out/types/graph.d.ts +3 -4
- package/out/types/graph.d.ts.map +1 -1
- package/out/types/requests.d.ts +22 -0
- package/out/types/requests.d.ts.map +1 -1
- package/out/utils/validators.d.ts +23 -0
- package/out/utils/validators.d.ts.map +1 -0
- package/out/utils/validators.js +124 -0
- package/package.json +2 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const api_1 = require("@forge/api");
|
|
4
4
|
const graph_1 = require("../graph");
|
|
5
|
+
const validators_1 = require("../utils/validators");
|
|
5
6
|
jest.mock('@forge/api');
|
|
6
7
|
describe('TeamWorkGraphClient - setEntities', () => {
|
|
7
8
|
let graphClient;
|
|
@@ -16,7 +17,7 @@ describe('TeamWorkGraphClient - setEntities', () => {
|
|
|
16
17
|
const req = { entities: [] };
|
|
17
18
|
await expect(graphClient.setEntities(req)).rejects.toThrow('entities array cannot be empty');
|
|
18
19
|
});
|
|
19
|
-
it(
|
|
20
|
+
it(`throws if more than ${validators_1.MAX_BULK_ENTITIES} entities`, async () => {
|
|
20
21
|
const documentEntity = {
|
|
21
22
|
schemaVersion: '1.0',
|
|
22
23
|
id: 'my-document',
|
|
@@ -48,9 +49,9 @@ describe('TeamWorkGraphClient - setEntities', () => {
|
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
51
|
const req = {
|
|
51
|
-
entities: Array(
|
|
52
|
+
entities: Array(validators_1.MAX_BULK_ENTITIES + 1).fill(documentEntity)
|
|
52
53
|
};
|
|
53
|
-
await expect(graphClient.setEntities(req)).rejects.toThrow(
|
|
54
|
+
await expect(graphClient.setEntities(req)).rejects.toThrow(`Bulk ingestion supports maximum ${validators_1.MAX_BULK_ENTITIES} entities`);
|
|
54
55
|
});
|
|
55
56
|
it('posts to /api/v1/entities/bulk and returns response', async () => {
|
|
56
57
|
const documentEntity = {
|
|
@@ -314,11 +315,11 @@ describe('TeamWorkGraphClient - deleteEntitiesByExternalId', () => {
|
|
|
314
315
|
})).rejects.toThrow('externalIds array cannot be empty');
|
|
315
316
|
});
|
|
316
317
|
it('should throw error when externalIds array exceeds limit', async () => {
|
|
317
|
-
const manyExternalIds = Array(
|
|
318
|
+
const manyExternalIds = Array(validators_1.MAX_BULK_ENTITIES_DELETE + 1).fill('pipelines/123/builds/456');
|
|
318
319
|
await expect(graphClient.deleteEntitiesByExternalId({
|
|
319
320
|
entityType: 'atlassian:document',
|
|
320
321
|
externalIds: manyExternalIds
|
|
321
|
-
})).rejects.toThrow(
|
|
322
|
+
})).rejects.toThrow(`Bulk entity deletion supports maximum ${validators_1.MAX_BULK_ENTITIES_DELETE} entities`);
|
|
322
323
|
});
|
|
323
324
|
it('should throw error when externalIds is not an array', async () => {
|
|
324
325
|
await expect(graphClient.deleteEntitiesByExternalId({
|
|
@@ -402,4 +403,80 @@ describe('TeamWorkGraphClient - deleteEntitiesByProperties', () => {
|
|
|
402
403
|
it('should throw error when properties object is empty', async () => {
|
|
403
404
|
await expect(graphClient.deleteEntitiesByProperties({})).rejects.toThrow('properties object cannot be empty');
|
|
404
405
|
});
|
|
406
|
+
it('posts branch entities to /api/v1/entities/bulk and returns response', async () => {
|
|
407
|
+
const branchEntity = {
|
|
408
|
+
schemaVersion: '2.0',
|
|
409
|
+
id: 'branch-1',
|
|
410
|
+
updateSequenceNumber: 1,
|
|
411
|
+
displayName: 'feature-branch',
|
|
412
|
+
url: 'https://github.com/org/repo/tree/feature-branch',
|
|
413
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
414
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
415
|
+
permissions: {
|
|
416
|
+
accessControls: [
|
|
417
|
+
{
|
|
418
|
+
principals: [
|
|
419
|
+
{
|
|
420
|
+
type: 'EVERYONE'
|
|
421
|
+
}
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
'atlassian:branch': {}
|
|
427
|
+
};
|
|
428
|
+
const req = { entities: [branchEntity] };
|
|
429
|
+
const expected = { success: true, results: [{ entityId: 'branch-1', success: true }] };
|
|
430
|
+
mockFetch.mockResolvedValueOnce({
|
|
431
|
+
ok: true,
|
|
432
|
+
json: () => Promise.resolve(expected)
|
|
433
|
+
});
|
|
434
|
+
const result = await graphClient.setEntities(req);
|
|
435
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
436
|
+
expect(result).toEqual(expected);
|
|
437
|
+
});
|
|
438
|
+
it('posts commit entities to /api/v1/entities/bulk and returns response', async () => {
|
|
439
|
+
const commitEntity = {
|
|
440
|
+
schemaVersion: '2.0',
|
|
441
|
+
id: 'commit-1',
|
|
442
|
+
updateSequenceNumber: 1,
|
|
443
|
+
displayName: 'abc123 - Add new feature',
|
|
444
|
+
url: 'https://github.com/org/repo/commit/abc123',
|
|
445
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
446
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
447
|
+
permissions: {
|
|
448
|
+
accessControls: [
|
|
449
|
+
{
|
|
450
|
+
principals: [
|
|
451
|
+
{
|
|
452
|
+
type: 'EVERYONE'
|
|
453
|
+
}
|
|
454
|
+
]
|
|
455
|
+
}
|
|
456
|
+
]
|
|
457
|
+
},
|
|
458
|
+
'atlassian:commit': {
|
|
459
|
+
flags: ['flag1', 'flag2'],
|
|
460
|
+
fileCount: 10,
|
|
461
|
+
files: [
|
|
462
|
+
{
|
|
463
|
+
path: 'path/to/file.txt',
|
|
464
|
+
url: 'https://github.com/org/repo/blob/abc123/path/to/file.txt',
|
|
465
|
+
changeType: 'ADDED',
|
|
466
|
+
linesAdded: 10,
|
|
467
|
+
linesRemoved: 5
|
|
468
|
+
}
|
|
469
|
+
]
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
const req = { entities: [commitEntity] };
|
|
473
|
+
const expected = { success: true, results: [{ entityId: 'commit-1', success: true }] };
|
|
474
|
+
mockFetch.mockResolvedValueOnce({
|
|
475
|
+
ok: true,
|
|
476
|
+
json: () => Promise.resolve(expected)
|
|
477
|
+
});
|
|
478
|
+
const result = await graphClient.setEntities(req);
|
|
479
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
480
|
+
expect(result).toEqual(expected);
|
|
481
|
+
});
|
|
405
482
|
});
|
|
@@ -6,22 +6,13 @@ jest.mock('@forge/api', () => ({
|
|
|
6
6
|
__fetchProduct: jest.fn(),
|
|
7
7
|
fetch: jest.fn()
|
|
8
8
|
}));
|
|
9
|
-
describe('
|
|
9
|
+
describe('TeamWorkGraphClient - Extended Features', () => {
|
|
10
10
|
let graphClient;
|
|
11
|
-
let mockContext;
|
|
12
11
|
beforeEach(() => {
|
|
13
12
|
graphClient = new graph_1.TeamWorkGraphClient();
|
|
14
|
-
mockContext = {
|
|
15
|
-
ingestionContext: { id: 'test' },
|
|
16
|
-
installContext: 'test-installation',
|
|
17
|
-
principal: { accountId: 'test' },
|
|
18
|
-
license: { isActive: true }
|
|
19
|
-
};
|
|
20
|
-
jest.spyOn(graphClient, 'saveToStage').mockImplementation(() => Promise.resolve());
|
|
21
|
-
jest.spyOn(graphClient, 'validateData').mockImplementation(() => Promise.resolve());
|
|
22
13
|
jest.clearAllMocks();
|
|
23
14
|
});
|
|
24
|
-
describe('
|
|
15
|
+
describe('fetchData', () => {
|
|
25
16
|
it('should successfully fetch and process external data', async () => {
|
|
26
17
|
const mockData = { items: [{ id: 1, name: 'Task 1' }] };
|
|
27
18
|
const mockResponse = {
|
|
@@ -30,33 +21,44 @@ describe('Teamwork Graph Client Extended Features', () => {
|
|
|
30
21
|
json: jest.fn().mockResolvedValue(mockData)
|
|
31
22
|
};
|
|
32
23
|
api_1.fetch.mockResolvedValue(mockResponse);
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
const request = {
|
|
25
|
+
requestConfig: {
|
|
26
|
+
url: 'https://api.gitbook.com/api/tasks',
|
|
27
|
+
method: 'GET',
|
|
28
|
+
headers: { Authorization: 'Bearer token' }
|
|
29
|
+
},
|
|
30
|
+
onResult: jest.fn()
|
|
37
31
|
};
|
|
38
|
-
const
|
|
39
|
-
const result = await graphClient.fetchData(mockContext, requestConfig, onResult);
|
|
32
|
+
const result = await graphClient.fetchData(request);
|
|
40
33
|
expect(api_1.fetch).toHaveBeenCalledWith('https://api.gitbook.com/api/tasks', {
|
|
41
34
|
method: 'GET',
|
|
42
35
|
headers: { Authorization: 'Bearer token' }
|
|
43
36
|
});
|
|
44
|
-
expect(onResult).toHaveBeenCalledWith(mockData);
|
|
45
|
-
expect(result).toEqual(
|
|
37
|
+
expect(request.onResult).toHaveBeenCalledWith(mockData);
|
|
38
|
+
expect(result).toEqual({
|
|
39
|
+
success: true,
|
|
40
|
+
data: mockData
|
|
41
|
+
});
|
|
46
42
|
});
|
|
47
|
-
it('should
|
|
43
|
+
it('should return error response when fetch fails', async () => {
|
|
48
44
|
const mockResponse = {
|
|
49
45
|
ok: false,
|
|
50
46
|
status: 401
|
|
51
47
|
};
|
|
52
48
|
api_1.fetch.mockResolvedValue(mockResponse);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
const request = {
|
|
50
|
+
requestConfig: {
|
|
51
|
+
url: 'https://api.gitbook.com/api/tasks',
|
|
52
|
+
method: 'GET'
|
|
53
|
+
},
|
|
54
|
+
onResult: jest.fn()
|
|
56
55
|
};
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
const result = await graphClient.fetchData(request);
|
|
57
|
+
expect(result).toEqual({
|
|
58
|
+
success: false,
|
|
59
|
+
error: 'Remote call failed with status: 401'
|
|
60
|
+
});
|
|
61
|
+
expect(request.onResult).not.toHaveBeenCalled();
|
|
60
62
|
});
|
|
61
63
|
});
|
|
62
64
|
describe('transformData', () => {
|
|
@@ -69,10 +71,32 @@ describe('Teamwork Graph Client Extended Features', () => {
|
|
|
69
71
|
type: 'task'
|
|
70
72
|
}))
|
|
71
73
|
}));
|
|
72
|
-
const
|
|
74
|
+
const request = {
|
|
75
|
+
data: inputData,
|
|
76
|
+
transformMethod
|
|
77
|
+
};
|
|
78
|
+
const result = await graphClient.transformData(request);
|
|
73
79
|
expect(transformMethod).toHaveBeenCalledWith(inputData);
|
|
74
80
|
expect(result).toEqual({
|
|
75
|
-
|
|
81
|
+
success: true,
|
|
82
|
+
transformedData: {
|
|
83
|
+
entities: [{ id: 'task-1', name: 'Task 1', type: 'task' }]
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
it('should return error response when transform method throws', async () => {
|
|
88
|
+
const inputData = { items: [{ id: 1, name: 'Task 1' }] };
|
|
89
|
+
const transformMethod = jest.fn().mockImplementation(() => {
|
|
90
|
+
throw new Error('Transform failed');
|
|
91
|
+
});
|
|
92
|
+
const request = {
|
|
93
|
+
data: inputData,
|
|
94
|
+
transformMethod
|
|
95
|
+
};
|
|
96
|
+
const result = await graphClient.transformData(request);
|
|
97
|
+
expect(result).toEqual({
|
|
98
|
+
success: false,
|
|
99
|
+
error: 'Transform failed'
|
|
76
100
|
});
|
|
77
101
|
});
|
|
78
102
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const api_1 = require("@forge/api");
|
|
4
4
|
const graph_1 = require("../graph");
|
|
5
|
+
const validators_1 = require("../utils/validators");
|
|
5
6
|
jest.mock('@forge/api');
|
|
6
7
|
describe('TeamWorkGraphClient - Group Operations', () => {
|
|
7
8
|
let graphClient;
|
|
@@ -87,10 +88,10 @@ describe('TeamWorkGraphClient - Group Operations', () => {
|
|
|
87
88
|
})).rejects.toThrow('groups array cannot be empty');
|
|
88
89
|
});
|
|
89
90
|
it('should throw error when groups array exceeds limit', async () => {
|
|
90
|
-
const manyGroups = Array(
|
|
91
|
+
const manyGroups = Array(validators_1.MAX_BULK_GROUPS + 1).fill(groupPayload);
|
|
91
92
|
await expect(graphClient.setGroups({
|
|
92
93
|
groups: manyGroups
|
|
93
|
-
})).rejects.toThrow(
|
|
94
|
+
})).rejects.toThrow(`Bulk group ingestion supports maximum ${validators_1.MAX_BULK_GROUPS} groups`);
|
|
94
95
|
});
|
|
95
96
|
it('should throw error when groups is not an array', async () => {
|
|
96
97
|
await expect(graphClient.setGroups({
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const api_1 = require("@forge/api");
|
|
4
4
|
const graph_1 = require("../graph");
|
|
5
|
+
const validators_1 = require("../utils/validators");
|
|
5
6
|
jest.mock('@forge/api');
|
|
6
7
|
describe('TeamWorkGraphClient - User Operations', () => {
|
|
7
8
|
let graphClient;
|
|
@@ -66,10 +67,10 @@ describe('TeamWorkGraphClient - User Operations', () => {
|
|
|
66
67
|
})).rejects.toThrow('users array cannot be empty');
|
|
67
68
|
});
|
|
68
69
|
it('should throw error when users array exceeds limit', async () => {
|
|
69
|
-
const manyUsers = Array(
|
|
70
|
+
const manyUsers = Array(validators_1.MAX_BULK_USERS + 1).fill(userPayload);
|
|
70
71
|
await expect(graphClient.setUsers({
|
|
71
72
|
users: manyUsers
|
|
72
|
-
})).rejects.toThrow(
|
|
73
|
+
})).rejects.toThrow(`Bulk user ingestion supports maximum ${validators_1.MAX_BULK_USERS} users`);
|
|
73
74
|
});
|
|
74
75
|
});
|
|
75
76
|
describe('deleteUsersByExternalId', () => {
|
|
@@ -256,10 +257,10 @@ describe('TeamWorkGraphClient - User Operations', () => {
|
|
|
256
257
|
})).rejects.toThrow('directMappings array cannot be empty');
|
|
257
258
|
});
|
|
258
259
|
it('should throw error when directMappings array exceeds limit', async () => {
|
|
259
|
-
const manyMappings = Array(
|
|
260
|
+
const manyMappings = Array(validators_1.MAX_USER_MAPPINGS + 1).fill(mappingWithAccountId);
|
|
260
261
|
await expect(graphClient.mapUsers({
|
|
261
262
|
directMappings: manyMappings
|
|
262
|
-
})).rejects.toThrow(
|
|
263
|
+
})).rejects.toThrow(`Bulk user mapping supports maximum ${validators_1.MAX_USER_MAPPINGS} mappings`);
|
|
263
264
|
});
|
|
264
265
|
it('should throw error when directMappings is not an array', async () => {
|
|
265
266
|
await expect(graphClient.mapUsers({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.test.d.ts","sourceRoot":"","sources":["../../src/__test__/validators.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const validators_1 = require("../utils/validators");
|
|
4
|
+
describe('TeamWorkGraphClient - Validators', () => {
|
|
5
|
+
describe('validateArray', () => {
|
|
6
|
+
it('should pass for valid array', () => {
|
|
7
|
+
expect(() => (0, validators_1.validateArray)([1, 2, 3], 'test')).not.toThrow();
|
|
8
|
+
});
|
|
9
|
+
it('should throw for non-array', () => {
|
|
10
|
+
expect(() => (0, validators_1.validateArray)('not an array', 'test')).toThrow('test must be an array');
|
|
11
|
+
});
|
|
12
|
+
it('should throw for empty array', () => {
|
|
13
|
+
expect(() => (0, validators_1.validateArray)([], 'test')).toThrow('test array cannot be empty');
|
|
14
|
+
});
|
|
15
|
+
it('should throw for null', () => {
|
|
16
|
+
expect(() => (0, validators_1.validateArray)(null, 'test')).toThrow('test must be an array');
|
|
17
|
+
});
|
|
18
|
+
it('should throw for undefined', () => {
|
|
19
|
+
expect(() => (0, validators_1.validateArray)(undefined, 'test')).toThrow('test must be an array');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe('validateArrayMaxLength', () => {
|
|
23
|
+
it('should pass for array within limit', () => {
|
|
24
|
+
expect(() => (0, validators_1.validateArrayMaxLength)([1, 2], 'test', 5)).not.toThrow();
|
|
25
|
+
});
|
|
26
|
+
it('should pass for array at limit', () => {
|
|
27
|
+
expect(() => (0, validators_1.validateArrayMaxLength)([1, 2, 3], 'test', 3)).not.toThrow();
|
|
28
|
+
});
|
|
29
|
+
it('should throw for array exceeding limit', () => {
|
|
30
|
+
expect(() => (0, validators_1.validateArrayMaxLength)([1, 2, 3, 4], 'test', 3)).toThrow('test supports maximum 3 items. Received 4');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
describe('validateRequiredString', () => {
|
|
34
|
+
it('should pass for valid string', () => {
|
|
35
|
+
expect(() => (0, validators_1.validateRequiredString)('valid string', 'test')).not.toThrow();
|
|
36
|
+
});
|
|
37
|
+
it('should throw for empty string', () => {
|
|
38
|
+
expect(() => (0, validators_1.validateRequiredString)('', 'test')).toThrow('test is required');
|
|
39
|
+
});
|
|
40
|
+
it('should throw for whitespace string', () => {
|
|
41
|
+
expect(() => (0, validators_1.validateRequiredString)(' ', 'test')).toThrow('test is required');
|
|
42
|
+
});
|
|
43
|
+
it('should throw for null', () => {
|
|
44
|
+
expect(() => (0, validators_1.validateRequiredString)(null, 'test')).toThrow('test is required');
|
|
45
|
+
});
|
|
46
|
+
it('should throw for undefined', () => {
|
|
47
|
+
expect(() => (0, validators_1.validateRequiredString)(undefined, 'test')).toThrow('test is required');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe('validateObject', () => {
|
|
51
|
+
it('should pass for valid object', () => {
|
|
52
|
+
expect(() => (0, validators_1.validateObject)({ key: 'value' }, 'test')).not.toThrow();
|
|
53
|
+
});
|
|
54
|
+
it('should throw for null', () => {
|
|
55
|
+
expect(() => (0, validators_1.validateObject)(null, 'test')).toThrow('test must be an object');
|
|
56
|
+
});
|
|
57
|
+
it('should throw for undefined', () => {
|
|
58
|
+
expect(() => (0, validators_1.validateObject)(undefined, 'test')).toThrow('test must be an object');
|
|
59
|
+
});
|
|
60
|
+
it('should throw for non-object', () => {
|
|
61
|
+
expect(() => (0, validators_1.validateObject)('not an object', 'test')).toThrow('test must be an object');
|
|
62
|
+
});
|
|
63
|
+
it('should throw for empty object', () => {
|
|
64
|
+
expect(() => (0, validators_1.validateObject)({}, 'test')).toThrow('test object cannot be empty');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('validateSetEntitiesRequest', () => {
|
|
68
|
+
it('should pass for valid entities array', () => {
|
|
69
|
+
const entities = Array(validators_1.MAX_BULK_ENTITIES).fill({ id: 'test' });
|
|
70
|
+
expect(() => (0, validators_1.validateSetEntitiesRequest)(entities)).not.toThrow();
|
|
71
|
+
});
|
|
72
|
+
it('should throw for non-array', () => {
|
|
73
|
+
expect(() => (0, validators_1.validateSetEntitiesRequest)('not array')).toThrow('entities must be an array');
|
|
74
|
+
});
|
|
75
|
+
it('should throw for empty array', () => {
|
|
76
|
+
expect(() => (0, validators_1.validateSetEntitiesRequest)([])).toThrow('entities array cannot be empty');
|
|
77
|
+
});
|
|
78
|
+
it('should throw for array exceeding limit', () => {
|
|
79
|
+
const entities = Array(validators_1.MAX_BULK_ENTITIES + 1).fill({ id: 'test' });
|
|
80
|
+
expect(() => (0, validators_1.validateSetEntitiesRequest)(entities)).toThrow(`Bulk ingestion supports maximum ${validators_1.MAX_BULK_ENTITIES} entities. Received ${validators_1.MAX_BULK_ENTITIES + 1}`);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe('validateSetUsersRequest', () => {
|
|
84
|
+
it('should pass for valid users array', () => {
|
|
85
|
+
const users = Array(validators_1.MAX_BULK_USERS).fill({ id: 'test' });
|
|
86
|
+
expect(() => (0, validators_1.validateSetUsersRequest)(users)).not.toThrow();
|
|
87
|
+
});
|
|
88
|
+
it('should throw for non-array', () => {
|
|
89
|
+
expect(() => (0, validators_1.validateSetUsersRequest)('not array')).toThrow('users must be an array');
|
|
90
|
+
});
|
|
91
|
+
it('should throw for empty array', () => {
|
|
92
|
+
expect(() => (0, validators_1.validateSetUsersRequest)([])).toThrow('users array cannot be empty');
|
|
93
|
+
});
|
|
94
|
+
it('should throw for array exceeding limit', () => {
|
|
95
|
+
const users = Array(validators_1.MAX_BULK_USERS + 1).fill({ id: 'test' });
|
|
96
|
+
expect(() => (0, validators_1.validateSetUsersRequest)(users)).toThrow(`Bulk user ingestion supports maximum ${validators_1.MAX_BULK_USERS} users. Received ${validators_1.MAX_BULK_USERS + 1}`);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('validateSetGroupsRequest', () => {
|
|
100
|
+
it('should pass for valid groups array', () => {
|
|
101
|
+
const groups = Array(validators_1.MAX_BULK_GROUPS).fill({ id: 'test' });
|
|
102
|
+
expect(() => (0, validators_1.validateSetGroupsRequest)(groups)).not.toThrow();
|
|
103
|
+
});
|
|
104
|
+
it('should throw for non-array', () => {
|
|
105
|
+
expect(() => (0, validators_1.validateSetGroupsRequest)('not array')).toThrow('groups must be an array');
|
|
106
|
+
});
|
|
107
|
+
it('should throw for empty array', () => {
|
|
108
|
+
expect(() => (0, validators_1.validateSetGroupsRequest)([])).toThrow('groups array cannot be empty');
|
|
109
|
+
});
|
|
110
|
+
it('should throw for array exceeding limit', () => {
|
|
111
|
+
const groups = Array(validators_1.MAX_BULK_GROUPS + 1).fill({ id: 'test' });
|
|
112
|
+
expect(() => (0, validators_1.validateSetGroupsRequest)(groups)).toThrow(`Bulk group ingestion supports maximum ${validators_1.MAX_BULK_GROUPS} groups. Received ${validators_1.MAX_BULK_GROUPS + 1}`);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('validateDeleteEntitiesByExternalIdRequest', () => {
|
|
116
|
+
it('should pass for valid request', () => {
|
|
117
|
+
const entityType = 'test-type';
|
|
118
|
+
const externalIds = Array(validators_1.MAX_BULK_ENTITIES_DELETE).fill('test-id');
|
|
119
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)(entityType, externalIds)).not.toThrow();
|
|
120
|
+
});
|
|
121
|
+
it('should throw for empty entityType', () => {
|
|
122
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)('', ['test'])).toThrow('entityType is required');
|
|
123
|
+
});
|
|
124
|
+
it('should throw for whitespace entityType', () => {
|
|
125
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)(' ', ['test'])).toThrow('entityType is required');
|
|
126
|
+
});
|
|
127
|
+
it('should throw for non-array externalIds', () => {
|
|
128
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)('type', 'not array')).toThrow('externalIds must be an array');
|
|
129
|
+
});
|
|
130
|
+
it('should throw for empty externalIds array', () => {
|
|
131
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)('type', [])).toThrow('externalIds array cannot be empty');
|
|
132
|
+
});
|
|
133
|
+
it('should throw for externalIds exceeding limit', () => {
|
|
134
|
+
const externalIds = Array(validators_1.MAX_BULK_ENTITIES_DELETE + 1).fill('test-id');
|
|
135
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByExternalIdRequest)('type', externalIds)).toThrow(`Bulk entity deletion supports maximum ${validators_1.MAX_BULK_ENTITIES_DELETE} entities. Received ${validators_1.MAX_BULK_ENTITIES_DELETE + 1}`);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
describe('validateDeleteUsersByExternalIdRequest', () => {
|
|
139
|
+
it('should pass for valid externalIds array', () => {
|
|
140
|
+
const externalIds = ['id1', 'id2'];
|
|
141
|
+
expect(() => (0, validators_1.validateDeleteUsersByExternalIdRequest)(externalIds)).not.toThrow();
|
|
142
|
+
});
|
|
143
|
+
it('should throw for non-array', () => {
|
|
144
|
+
expect(() => (0, validators_1.validateDeleteUsersByExternalIdRequest)('not array')).toThrow('externalIds must be an array');
|
|
145
|
+
});
|
|
146
|
+
it('should throw for empty array', () => {
|
|
147
|
+
expect(() => (0, validators_1.validateDeleteUsersByExternalIdRequest)([])).toThrow('externalIds array cannot be empty');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
describe('validateDeleteGroupsByExternalIdRequest', () => {
|
|
151
|
+
it('should pass for valid externalIds array', () => {
|
|
152
|
+
const externalIds = ['id1', 'id2'];
|
|
153
|
+
expect(() => (0, validators_1.validateDeleteGroupsByExternalIdRequest)(externalIds)).not.toThrow();
|
|
154
|
+
});
|
|
155
|
+
it('should throw for non-array', () => {
|
|
156
|
+
expect(() => (0, validators_1.validateDeleteGroupsByExternalIdRequest)('not array')).toThrow('externalIds must be an array');
|
|
157
|
+
});
|
|
158
|
+
it('should throw for empty array', () => {
|
|
159
|
+
expect(() => (0, validators_1.validateDeleteGroupsByExternalIdRequest)([])).toThrow('externalIds array cannot be empty');
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
describe('validateGetEntityByExternalIdRequest', () => {
|
|
163
|
+
it('should pass for valid request', () => {
|
|
164
|
+
expect(() => (0, validators_1.validateGetEntityByExternalIdRequest)('type', 'id')).not.toThrow();
|
|
165
|
+
});
|
|
166
|
+
it('should throw for empty entityType', () => {
|
|
167
|
+
expect(() => (0, validators_1.validateGetEntityByExternalIdRequest)('', 'id')).toThrow('entityType is required');
|
|
168
|
+
});
|
|
169
|
+
it('should throw for empty externalId', () => {
|
|
170
|
+
expect(() => (0, validators_1.validateGetEntityByExternalIdRequest)('type', '')).toThrow('externalId is required');
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
describe('validateGetUserByExternalIdRequest', () => {
|
|
174
|
+
it('should pass for valid externalId', () => {
|
|
175
|
+
expect(() => (0, validators_1.validateGetUserByExternalIdRequest)('valid-id')).not.toThrow();
|
|
176
|
+
});
|
|
177
|
+
it('should throw for empty externalId', () => {
|
|
178
|
+
expect(() => (0, validators_1.validateGetUserByExternalIdRequest)('')).toThrow('externalId is required');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('validateGetGroupByExternalIdRequest', () => {
|
|
182
|
+
it('should pass for valid externalId', () => {
|
|
183
|
+
expect(() => (0, validators_1.validateGetGroupByExternalIdRequest)('valid-id')).not.toThrow();
|
|
184
|
+
});
|
|
185
|
+
it('should throw for empty externalId', () => {
|
|
186
|
+
expect(() => (0, validators_1.validateGetGroupByExternalIdRequest)('')).toThrow('externalId is required');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe('validateMapUsersRequest', () => {
|
|
190
|
+
it('should pass for valid mappings', () => {
|
|
191
|
+
const directMappings = [
|
|
192
|
+
{ externalId: 'id1', accountId: 'acc1' },
|
|
193
|
+
{ externalId: 'id2', externalEmailAddress: 'email@test.com' }
|
|
194
|
+
];
|
|
195
|
+
expect(() => (0, validators_1.validateMapUsersRequest)(directMappings)).not.toThrow();
|
|
196
|
+
});
|
|
197
|
+
it('should throw for non-array', () => {
|
|
198
|
+
expect(() => (0, validators_1.validateMapUsersRequest)('not array')).toThrow('directMappings must be an array');
|
|
199
|
+
});
|
|
200
|
+
it('should throw for empty array', () => {
|
|
201
|
+
expect(() => (0, validators_1.validateMapUsersRequest)([])).toThrow('directMappings array cannot be empty');
|
|
202
|
+
});
|
|
203
|
+
it('should throw for array exceeding limit', () => {
|
|
204
|
+
const directMappings = Array(validators_1.MAX_USER_MAPPINGS + 1).fill({ externalId: 'id', accountId: 'acc' });
|
|
205
|
+
expect(() => (0, validators_1.validateMapUsersRequest)(directMappings)).toThrow(`Bulk user mapping supports maximum ${validators_1.MAX_USER_MAPPINGS} mappings. Received ${validators_1.MAX_USER_MAPPINGS + 1}`);
|
|
206
|
+
});
|
|
207
|
+
it('should throw for mapping without accountId or externalEmailAddress', () => {
|
|
208
|
+
const directMappings = [{ externalId: 'id' }];
|
|
209
|
+
expect(() => (0, validators_1.validateMapUsersRequest)(directMappings)).toThrow('Each mapping must have either accountId or externalEmailAddress');
|
|
210
|
+
});
|
|
211
|
+
it('should throw for mapping without externalId', () => {
|
|
212
|
+
const directMappings = [{ accountId: 'acc' }];
|
|
213
|
+
expect(() => (0, validators_1.validateMapUsersRequest)(directMappings)).toThrow('Each mapping must have an externalId');
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
describe('validateDeleteEntitiesByPropertiesRequest', () => {
|
|
217
|
+
it('should pass for valid properties object', () => {
|
|
218
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByPropertiesRequest)({ key: 'value' })).not.toThrow();
|
|
219
|
+
});
|
|
220
|
+
it('should throw for null', () => {
|
|
221
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByPropertiesRequest)(null)).toThrow('properties must be an object');
|
|
222
|
+
});
|
|
223
|
+
it('should throw for non-object', () => {
|
|
224
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByPropertiesRequest)('not object')).toThrow('properties must be an object');
|
|
225
|
+
});
|
|
226
|
+
it('should throw for empty object', () => {
|
|
227
|
+
expect(() => (0, validators_1.validateDeleteEntitiesByPropertiesRequest)({})).toThrow('properties object cannot be empty');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
describe('validateFetchDataRequest', () => {
|
|
231
|
+
it('should pass for valid request', () => {
|
|
232
|
+
const request = {
|
|
233
|
+
requestConfig: {
|
|
234
|
+
url: 'https://test.com',
|
|
235
|
+
method: 'GET',
|
|
236
|
+
headers: { 'Content-Type': 'application/json' }
|
|
237
|
+
},
|
|
238
|
+
onResult: () => {
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).not.toThrow();
|
|
242
|
+
});
|
|
243
|
+
it('should throw for null request', () => {
|
|
244
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(null)).toThrow('request must be an object');
|
|
245
|
+
});
|
|
246
|
+
it('should throw for non-object request', () => {
|
|
247
|
+
expect(() => (0, validators_1.validateFetchDataRequest)('not object')).toThrow('request must be an object');
|
|
248
|
+
});
|
|
249
|
+
it('should throw for missing requestConfig', () => {
|
|
250
|
+
const request = {
|
|
251
|
+
onResult: () => {
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig is required and must be an object');
|
|
255
|
+
});
|
|
256
|
+
it('should throw for non-object requestConfig', () => {
|
|
257
|
+
const request = {
|
|
258
|
+
requestConfig: 'not object',
|
|
259
|
+
onResult: () => {
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig is required and must be an object');
|
|
263
|
+
});
|
|
264
|
+
it('should throw for missing url', () => {
|
|
265
|
+
const request = {
|
|
266
|
+
requestConfig: { method: 'GET' },
|
|
267
|
+
onResult: () => {
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig.url is required and must be a string');
|
|
271
|
+
});
|
|
272
|
+
it('should throw for non-string url', () => {
|
|
273
|
+
const request = {
|
|
274
|
+
requestConfig: { url: 123, method: 'GET' },
|
|
275
|
+
onResult: () => {
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig.url is required and must be a string');
|
|
279
|
+
});
|
|
280
|
+
it('should throw for missing method', () => {
|
|
281
|
+
const request = {
|
|
282
|
+
requestConfig: { url: 'https://test.com' },
|
|
283
|
+
onResult: () => {
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig.method is required and must be a string');
|
|
287
|
+
});
|
|
288
|
+
it('should throw for non-string method', () => {
|
|
289
|
+
const request = {
|
|
290
|
+
requestConfig: { url: 'https://test.com', method: 123 },
|
|
291
|
+
onResult: () => {
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('requestConfig.method is required and must be a string');
|
|
295
|
+
});
|
|
296
|
+
it('should throw for missing onResult', () => {
|
|
297
|
+
const request = { requestConfig: { url: 'https://test.com', method: 'GET' } };
|
|
298
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('onResult is required and must be a function');
|
|
299
|
+
});
|
|
300
|
+
it('should throw for non-function onResult', () => {
|
|
301
|
+
const request = { requestConfig: { url: 'https://test.com', method: 'GET' }, onResult: 'not function' };
|
|
302
|
+
expect(() => (0, validators_1.validateFetchDataRequest)(request)).toThrow('onResult is required and must be a function');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
describe('validateTransformDataRequest', () => {
|
|
306
|
+
it('should pass for valid request', () => {
|
|
307
|
+
const request = {
|
|
308
|
+
data: { test: 'data' },
|
|
309
|
+
transformMethod: () => {
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
expect(() => (0, validators_1.validateTransformDataRequest)(request)).not.toThrow();
|
|
313
|
+
});
|
|
314
|
+
it('should throw for null request', () => {
|
|
315
|
+
expect(() => (0, validators_1.validateTransformDataRequest)(null)).toThrow('request must be an object');
|
|
316
|
+
});
|
|
317
|
+
it('should throw for non-object request', () => {
|
|
318
|
+
expect(() => (0, validators_1.validateTransformDataRequest)('not object')).toThrow('request must be an object');
|
|
319
|
+
});
|
|
320
|
+
it('should throw for missing transformMethod', () => {
|
|
321
|
+
const request = { data: { test: 'data' } };
|
|
322
|
+
expect(() => (0, validators_1.validateTransformDataRequest)(request)).toThrow('transformMethod is required and must be a function');
|
|
323
|
+
});
|
|
324
|
+
it('should throw for non-function transformMethod', () => {
|
|
325
|
+
const request = { data: { test: 'data' }, transformMethod: 'not function' };
|
|
326
|
+
expect(() => (0, validators_1.validateTransformDataRequest)(request)).toThrow('transformMethod is required and must be a function');
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
});
|