@forge/teamwork-graph 2.0.0-next.6 → 2.0.0-next.7
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 +615 -10
- package/out/__test__/error-handling.test.js +38 -96
- package/out/__test__/graph-extended.test.js +12 -2
- package/out/__test__/group-operations.test.js +5 -4
- package/out/__test__/user-operations.test.js +16 -5
- package/out/__test__/validators.test.js +254 -218
- package/out/graph.d.ts +0 -3
- package/out/graph.d.ts.map +1 -1
- package/out/graph.js +121 -91
- package/out/index.d.ts +1 -2
- package/out/index.d.ts.map +1 -1
- package/out/index.js +1 -4
- package/out/types/entities/index.d.ts +11 -2
- package/out/types/entities/index.d.ts.map +1 -1
- package/out/types/entities/project.d.ts +40 -0
- package/out/types/entities/project.d.ts.map +1 -0
- package/out/types/entities/project.js +2 -0
- package/out/types/entities/pull-request.d.ts +44 -0
- package/out/types/entities/pull-request.d.ts.map +1 -0
- package/out/types/entities/pull-request.js +2 -0
- package/out/types/entities/remote-link.d.ts +33 -0
- package/out/types/entities/remote-link.d.ts.map +1 -0
- package/out/types/entities/remote-link.js +2 -0
- package/out/types/entities/repository.d.ts +14 -0
- package/out/types/entities/repository.d.ts.map +1 -0
- package/out/types/entities/repository.js +2 -0
- package/out/types/entities/software-service.d.ts +17 -0
- package/out/types/entities/software-service.d.ts.map +1 -0
- package/out/types/entities/software-service.js +2 -0
- package/out/types/entities/space.d.ts +21 -0
- package/out/types/entities/space.d.ts.map +1 -0
- package/out/types/entities/space.js +2 -0
- package/out/types/entities/video.d.ts +48 -0
- package/out/types/entities/video.d.ts.map +1 -0
- package/out/types/entities/video.js +2 -0
- package/out/types/entities/work-item.d.ts +44 -0
- package/out/types/entities/work-item.d.ts.map +1 -0
- package/out/types/entities/work-item.js +2 -0
- package/out/types/entities/worker.d.ts +23 -0
- package/out/types/entities/worker.d.ts.map +1 -0
- package/out/types/entities/worker.js +2 -0
- package/out/types/requests.d.ts +29 -8
- package/out/types/requests.d.ts.map +1 -1
- package/out/utils/error-handling.d.ts +4 -0
- package/out/utils/error-handling.d.ts.map +1 -0
- package/out/utils/error-handling.js +77 -0
- package/out/utils/errors.d.ts +21 -15
- package/out/utils/errors.d.ts.map +1 -1
- package/out/utils/errors.js +43 -15
- package/out/utils/validators.d.ts.map +1 -1
- package/out/utils/validators.js +18 -15
- package/package.json +1 -1
- package/out/error-handling.d.ts +0 -3
- package/out/error-handling.d.ts.map +0 -1
- package/out/error-handling.js +0 -36
|
@@ -14,10 +14,11 @@ describe('TeamWorkGraphClient - setEntities', () => {
|
|
|
14
14
|
jest.clearAllMocks();
|
|
15
15
|
});
|
|
16
16
|
it('throws if entities array is empty', async () => {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
await expect(graphClient.setEntities({
|
|
18
|
+
entities: []
|
|
19
|
+
})).rejects.toThrow('entities array cannot be empty');
|
|
19
20
|
});
|
|
20
|
-
it(
|
|
21
|
+
it('throws if more than 100 entities', async () => {
|
|
21
22
|
const documentEntity = {
|
|
22
23
|
schemaVersion: '1.0',
|
|
23
24
|
id: 'my-document',
|
|
@@ -48,10 +49,10 @@ describe('TeamWorkGraphClient - setEntities', () => {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
};
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const manyEntities = Array(validators_1.MAX_BULK_ENTITIES + 1).fill(documentEntity);
|
|
53
|
+
await expect(graphClient.setEntities({
|
|
54
|
+
entities: manyEntities
|
|
55
|
+
})).rejects.toThrow(`Bulk ingestion supports maximum ${validators_1.MAX_BULK_ENTITIES} entities. Received ${validators_1.MAX_BULK_ENTITIES + 1}`);
|
|
55
56
|
});
|
|
56
57
|
it('posts to /api/v1/entities/bulk and returns response', async () => {
|
|
57
58
|
const documentEntity = {
|
|
@@ -238,10 +239,10 @@ describe('TeamWorkGraphClient - getEntityByExternalId', () => {
|
|
|
238
239
|
headers: {
|
|
239
240
|
get: () => null
|
|
240
241
|
},
|
|
241
|
-
|
|
242
|
+
json: () => Promise.resolve({
|
|
242
243
|
code: 'ENTITY_NOT_FOUND',
|
|
243
244
|
message: 'Entity not found'
|
|
244
|
-
})
|
|
245
|
+
})
|
|
245
246
|
};
|
|
246
247
|
mockFetch.mockResolvedValueOnce(errorResponse);
|
|
247
248
|
const result = await graphClient.getEntityByExternalId({
|
|
@@ -250,7 +251,8 @@ describe('TeamWorkGraphClient - getEntityByExternalId', () => {
|
|
|
250
251
|
});
|
|
251
252
|
expect(result).toEqual({
|
|
252
253
|
success: false,
|
|
253
|
-
error: 'Entity not found'
|
|
254
|
+
error: 'Failed to get entity by external ID: Not Found - Entity not found',
|
|
255
|
+
originalError: expect.any(Error)
|
|
254
256
|
});
|
|
255
257
|
});
|
|
256
258
|
it('should throw error when entityType is missing', async () => {
|
|
@@ -1019,4 +1021,607 @@ describe('TeamWorkGraphClient - deleteEntitiesByProperties', () => {
|
|
|
1019
1021
|
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1020
1022
|
expect(result).toEqual(expected);
|
|
1021
1023
|
});
|
|
1024
|
+
it('posts project entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1025
|
+
const projectEntity = {
|
|
1026
|
+
schemaVersion: '2.0',
|
|
1027
|
+
id: 'project-1',
|
|
1028
|
+
updateSequenceNumber: 1,
|
|
1029
|
+
displayName: 'E-commerce Platform Redesign',
|
|
1030
|
+
description: 'Complete redesign of the e-commerce platform with modern UI/UX and improved performance',
|
|
1031
|
+
url: 'https://jira.example.com/projects/ECOM-123',
|
|
1032
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1033
|
+
createdBy: {
|
|
1034
|
+
externalId: 'creator-user-123',
|
|
1035
|
+
userName: 'jdoe',
|
|
1036
|
+
displayName: 'John Doe',
|
|
1037
|
+
emails: [
|
|
1038
|
+
{
|
|
1039
|
+
value: 'john.doe@example.com',
|
|
1040
|
+
primary: true
|
|
1041
|
+
}
|
|
1042
|
+
]
|
|
1043
|
+
},
|
|
1044
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1045
|
+
permissions: {
|
|
1046
|
+
accessControls: [
|
|
1047
|
+
{
|
|
1048
|
+
principals: [
|
|
1049
|
+
{
|
|
1050
|
+
type: 'EVERYONE'
|
|
1051
|
+
}
|
|
1052
|
+
]
|
|
1053
|
+
}
|
|
1054
|
+
]
|
|
1055
|
+
},
|
|
1056
|
+
'atlassian:project': {
|
|
1057
|
+
key: 'ECOM-123',
|
|
1058
|
+
dueDate: '2024-12-31T23:59:59.000Z',
|
|
1059
|
+
priority: 'High',
|
|
1060
|
+
assignee: {
|
|
1061
|
+
accountId: 'project-manager-123',
|
|
1062
|
+
ari: 'ari:cloud:identity::user/project-manager-123',
|
|
1063
|
+
externalId: 'project-manager-123',
|
|
1064
|
+
name: 'Sarah Johnson',
|
|
1065
|
+
email: 'sarah.johnson@example.com',
|
|
1066
|
+
userName: 'sjohnson',
|
|
1067
|
+
avatar: 'https://avatar.example.com/sarah.jpg'
|
|
1068
|
+
},
|
|
1069
|
+
status: 'In Progress',
|
|
1070
|
+
attachments: [
|
|
1071
|
+
{
|
|
1072
|
+
url: 'https://files.example.com/project-spec.pdf',
|
|
1073
|
+
thumbnailUrl: 'https://files.example.com/thumbnails/project-spec.jpg',
|
|
1074
|
+
title: 'Project Specification Document',
|
|
1075
|
+
mimeType: 'application/pdf',
|
|
1076
|
+
byteSize: 2048000
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
url: 'https://files.example.com/wireframes.figma',
|
|
1080
|
+
thumbnailUrl: 'https://files.example.com/thumbnails/wireframes.jpg',
|
|
1081
|
+
title: 'UI Wireframes',
|
|
1082
|
+
mimeType: 'application/figma',
|
|
1083
|
+
byteSize: 1024000
|
|
1084
|
+
}
|
|
1085
|
+
],
|
|
1086
|
+
labels: ['frontend', 'redesign', 'high-priority'],
|
|
1087
|
+
environment: 'production',
|
|
1088
|
+
resolution: 'In Progress',
|
|
1089
|
+
votesCount: 12,
|
|
1090
|
+
watchersCount: 8
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
const req = { entities: [projectEntity] };
|
|
1094
|
+
const expected = { success: true, results: [{ entityId: 'project-1', success: true }] };
|
|
1095
|
+
mockFetch.mockResolvedValueOnce({
|
|
1096
|
+
ok: true,
|
|
1097
|
+
json: () => Promise.resolve(expected)
|
|
1098
|
+
});
|
|
1099
|
+
const result = await graphClient.setEntities(req);
|
|
1100
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1101
|
+
expect(result).toEqual(expected);
|
|
1102
|
+
});
|
|
1103
|
+
it('posts pull request entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1104
|
+
const pullRequestEntity = {
|
|
1105
|
+
schemaVersion: '2.0',
|
|
1106
|
+
id: 'pr-1',
|
|
1107
|
+
updateSequenceNumber: 1,
|
|
1108
|
+
displayName: 'Add user authentication feature',
|
|
1109
|
+
description: 'Implement OAuth2 authentication system with JWT tokens for enhanced security',
|
|
1110
|
+
url: 'https://github.com/company/repo/pull/42',
|
|
1111
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1112
|
+
containerKey: {
|
|
1113
|
+
type: 'atlassian:repository',
|
|
1114
|
+
value: {
|
|
1115
|
+
entityId: 'repo-company-main-123'
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
1118
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1119
|
+
permissions: {
|
|
1120
|
+
accessControls: [
|
|
1121
|
+
{
|
|
1122
|
+
principals: [
|
|
1123
|
+
{
|
|
1124
|
+
type: 'EVERYONE'
|
|
1125
|
+
}
|
|
1126
|
+
]
|
|
1127
|
+
}
|
|
1128
|
+
]
|
|
1129
|
+
},
|
|
1130
|
+
'atlassian:pull-request': {
|
|
1131
|
+
title: 'Add user authentication feature',
|
|
1132
|
+
displayId: 'PR-42',
|
|
1133
|
+
status: 'OPEN',
|
|
1134
|
+
author: {
|
|
1135
|
+
accountId: 'author-dev-456',
|
|
1136
|
+
externalId: 'author-dev-456',
|
|
1137
|
+
name: 'John Smith',
|
|
1138
|
+
userName: 'jsmith',
|
|
1139
|
+
email: 'john.smith@example.com',
|
|
1140
|
+
avatar: 'https://avatar.example.com/john.jpg',
|
|
1141
|
+
url: 'https://github.com/jsmith'
|
|
1142
|
+
},
|
|
1143
|
+
commentCount: 8,
|
|
1144
|
+
sourceBranch: 'feature/oauth2-auth',
|
|
1145
|
+
sourceBranchUrl: 'https://github.com/company/repo/tree/feature/oauth2-auth',
|
|
1146
|
+
destinationBranch: 'main',
|
|
1147
|
+
destinationBranchUrl: 'https://github.com/company/repo/tree/main',
|
|
1148
|
+
reviewers: [
|
|
1149
|
+
{
|
|
1150
|
+
accountId: 'reviewer-senior-789',
|
|
1151
|
+
id: 'reviewer-senior-789',
|
|
1152
|
+
email: 'alice.johnson@example.com',
|
|
1153
|
+
approvalStatus: 'approved',
|
|
1154
|
+
name: 'Alice Johnson',
|
|
1155
|
+
avatar: 'https://avatar.example.com/alice.jpg',
|
|
1156
|
+
url: 'https://github.com/alicejohnson',
|
|
1157
|
+
ari: 'ari:cloud:identity::user/reviewer-senior-789'
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
accountId: 'reviewer-lead-321',
|
|
1161
|
+
id: 'reviewer-lead-321',
|
|
1162
|
+
email: 'bob.wilson@example.com',
|
|
1163
|
+
approvalStatus: 'unapproved',
|
|
1164
|
+
name: 'Bob Wilson',
|
|
1165
|
+
avatar: 'https://avatar.example.com/bob.jpg',
|
|
1166
|
+
url: 'https://github.com/bobwilson',
|
|
1167
|
+
ari: 'ari:cloud:identity::user/reviewer-lead-321'
|
|
1168
|
+
}
|
|
1169
|
+
],
|
|
1170
|
+
taskCount: 3
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
const req = { entities: [pullRequestEntity] };
|
|
1174
|
+
const expected = { success: true, results: [{ entityId: 'pr-1', success: true }] };
|
|
1175
|
+
mockFetch.mockResolvedValueOnce({
|
|
1176
|
+
ok: true,
|
|
1177
|
+
json: () => Promise.resolve(expected)
|
|
1178
|
+
});
|
|
1179
|
+
const result = await graphClient.setEntities(req);
|
|
1180
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1181
|
+
expect(result).toEqual(expected);
|
|
1182
|
+
});
|
|
1183
|
+
it('posts remote link entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1184
|
+
const remoteLinkEntity = {
|
|
1185
|
+
schemaVersion: '2.0',
|
|
1186
|
+
id: 'remote-link-1',
|
|
1187
|
+
updateSequenceNumber: 1,
|
|
1188
|
+
displayName: 'JIRA Issue Link - Fix user authentication bug',
|
|
1189
|
+
url: 'https://company.atlassian.net/browse/AUTH-123',
|
|
1190
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1191
|
+
permissions: {
|
|
1192
|
+
accessControls: [
|
|
1193
|
+
{
|
|
1194
|
+
principals: [
|
|
1195
|
+
{
|
|
1196
|
+
type: 'EVERYONE'
|
|
1197
|
+
}
|
|
1198
|
+
]
|
|
1199
|
+
}
|
|
1200
|
+
]
|
|
1201
|
+
},
|
|
1202
|
+
'atlassian:remote-link': {
|
|
1203
|
+
type: 'issue',
|
|
1204
|
+
status: {
|
|
1205
|
+
appearance: 'in_progress',
|
|
1206
|
+
label: 'In Progress'
|
|
1207
|
+
},
|
|
1208
|
+
actionIds: ['view', 'edit', 'comment'],
|
|
1209
|
+
attributeMap: {
|
|
1210
|
+
priority: 'high',
|
|
1211
|
+
storyPoints: 5,
|
|
1212
|
+
sprint: 'Sprint 23',
|
|
1213
|
+
component: 'Authentication Service'
|
|
1214
|
+
},
|
|
1215
|
+
author: {
|
|
1216
|
+
accountId: 'author-dev-789',
|
|
1217
|
+
externalId: 'author-dev-789',
|
|
1218
|
+
name: 'Sarah Johnson',
|
|
1219
|
+
userName: 'sjohnson',
|
|
1220
|
+
email: 'sarah.johnson@example.com',
|
|
1221
|
+
avatar: 'https://avatar.example.com/sarah.jpg',
|
|
1222
|
+
url: 'https://company.atlassian.net/people/sarah.johnson'
|
|
1223
|
+
},
|
|
1224
|
+
category: 'bug',
|
|
1225
|
+
assignee: {
|
|
1226
|
+
accountId: 'assignee-dev-456',
|
|
1227
|
+
externalId: 'assignee-dev-456',
|
|
1228
|
+
name: 'Michael Chen',
|
|
1229
|
+
userName: 'mchen',
|
|
1230
|
+
email: 'michael.chen@example.com',
|
|
1231
|
+
avatar: 'https://avatar.example.com/michael.jpg',
|
|
1232
|
+
url: 'https://company.atlassian.net/people/michael.chen'
|
|
1233
|
+
},
|
|
1234
|
+
fullNounThirdPartyAri: 'ari:cloud:jira:company-site:issue/AUTH-123'
|
|
1235
|
+
}
|
|
1236
|
+
};
|
|
1237
|
+
const req = { entities: [remoteLinkEntity] };
|
|
1238
|
+
const expected = { success: true, results: [{ entityId: 'remote-link-1', success: true }] };
|
|
1239
|
+
mockFetch.mockResolvedValueOnce({
|
|
1240
|
+
ok: true,
|
|
1241
|
+
json: () => Promise.resolve(expected)
|
|
1242
|
+
});
|
|
1243
|
+
const result = await graphClient.setEntities(req);
|
|
1244
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1245
|
+
expect(result).toEqual(expected);
|
|
1246
|
+
});
|
|
1247
|
+
it('posts repository entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1248
|
+
const repositoryEntity = {
|
|
1249
|
+
schemaVersion: '2.0',
|
|
1250
|
+
id: 'repository-1',
|
|
1251
|
+
updateSequenceNumber: 1,
|
|
1252
|
+
displayName: 'E-commerce Platform Backend',
|
|
1253
|
+
url: 'https://github.com/company/ecommerce-backend',
|
|
1254
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1255
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1256
|
+
permissions: {
|
|
1257
|
+
accessControls: [
|
|
1258
|
+
{
|
|
1259
|
+
principals: [
|
|
1260
|
+
{
|
|
1261
|
+
type: 'EVERYONE'
|
|
1262
|
+
}
|
|
1263
|
+
]
|
|
1264
|
+
}
|
|
1265
|
+
]
|
|
1266
|
+
},
|
|
1267
|
+
'atlassian:repository': {
|
|
1268
|
+
name: 'ecommerce-backend',
|
|
1269
|
+
forkOf: 'https://github.com/upstream/ecommerce-platform',
|
|
1270
|
+
avatar: 'https://avatars.githubusercontent.com/u/company?v=4',
|
|
1271
|
+
avatarDescription: 'Company logo representing the ecommerce backend repository'
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1274
|
+
const req = { entities: [repositoryEntity] };
|
|
1275
|
+
const expected = { success: true, results: [{ entityId: 'repository-1', success: true }] };
|
|
1276
|
+
mockFetch.mockResolvedValueOnce({
|
|
1277
|
+
ok: true,
|
|
1278
|
+
json: () => Promise.resolve(expected)
|
|
1279
|
+
});
|
|
1280
|
+
const result = await graphClient.setEntities(req);
|
|
1281
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1282
|
+
expect(result).toEqual(expected);
|
|
1283
|
+
});
|
|
1284
|
+
it('posts software service entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1285
|
+
const softwareServiceEntity = {
|
|
1286
|
+
schemaVersion: '2.0',
|
|
1287
|
+
id: 'software-service-1',
|
|
1288
|
+
updateSequenceNumber: 1,
|
|
1289
|
+
displayName: 'Payment Processing Service',
|
|
1290
|
+
url: 'https://monitoring.example.com/services/payment-processor',
|
|
1291
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1292
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1293
|
+
permissions: {
|
|
1294
|
+
accessControls: [
|
|
1295
|
+
{
|
|
1296
|
+
principals: [
|
|
1297
|
+
{
|
|
1298
|
+
type: 'EVERYONE'
|
|
1299
|
+
}
|
|
1300
|
+
]
|
|
1301
|
+
}
|
|
1302
|
+
]
|
|
1303
|
+
},
|
|
1304
|
+
'atlassian:software-service': {
|
|
1305
|
+
description: 'Microservice responsible for processing all payment transactions with secure payment gateway integration',
|
|
1306
|
+
associationsMetadata: {
|
|
1307
|
+
ownership: 'payments-team',
|
|
1308
|
+
alertingChannel: '#payments-alerts',
|
|
1309
|
+
documentationUrl: 'https://docs.example.com/payment-service',
|
|
1310
|
+
repository: 'https://github.com/company/payment-processor',
|
|
1311
|
+
dashboardUrl: 'https://grafana.example.com/payment-service'
|
|
1312
|
+
},
|
|
1313
|
+
namespace: 'payment-system',
|
|
1314
|
+
environment: 'production',
|
|
1315
|
+
tags: ['payment', 'critical', 'pci-compliant', 'microservice', 'high-availability'],
|
|
1316
|
+
tier: 'tier-1',
|
|
1317
|
+
serviceType: 'REST API'
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
const req = { entities: [softwareServiceEntity] };
|
|
1321
|
+
const expected = { success: true, results: [{ entityId: 'software-service-1', success: true }] };
|
|
1322
|
+
mockFetch.mockResolvedValueOnce({
|
|
1323
|
+
ok: true,
|
|
1324
|
+
json: () => Promise.resolve(expected)
|
|
1325
|
+
});
|
|
1326
|
+
const result = await graphClient.setEntities(req);
|
|
1327
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1328
|
+
expect(result).toEqual(expected);
|
|
1329
|
+
});
|
|
1330
|
+
it('posts space entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1331
|
+
const spaceEntity = {
|
|
1332
|
+
schemaVersion: '2.0',
|
|
1333
|
+
id: 'space-1',
|
|
1334
|
+
updateSequenceNumber: 1,
|
|
1335
|
+
displayName: 'Engineering Team Documentation',
|
|
1336
|
+
url: 'https://company.atlassian.net/wiki/spaces/ENGDOC',
|
|
1337
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1338
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1339
|
+
permissions: {
|
|
1340
|
+
accessControls: [
|
|
1341
|
+
{
|
|
1342
|
+
principals: [
|
|
1343
|
+
{
|
|
1344
|
+
type: 'EVERYONE'
|
|
1345
|
+
}
|
|
1346
|
+
]
|
|
1347
|
+
}
|
|
1348
|
+
]
|
|
1349
|
+
},
|
|
1350
|
+
'atlassian:space': {
|
|
1351
|
+
key: 'ENGDOC',
|
|
1352
|
+
spaceType: 'global',
|
|
1353
|
+
subtype: 'documentation',
|
|
1354
|
+
icon: {
|
|
1355
|
+
url: 'https://company.atlassian.net/wiki/aa-avatar/5f7e8c123456789',
|
|
1356
|
+
width: 64,
|
|
1357
|
+
height: 64,
|
|
1358
|
+
isDefault: false
|
|
1359
|
+
},
|
|
1360
|
+
labels: ['engineering', 'documentation', 'team-resources', 'best-practices', 'onboarding']
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
const req = { entities: [spaceEntity] };
|
|
1364
|
+
const expected = { success: true, results: [{ entityId: 'space-1', success: true }] };
|
|
1365
|
+
mockFetch.mockResolvedValueOnce({
|
|
1366
|
+
ok: true,
|
|
1367
|
+
json: () => Promise.resolve(expected)
|
|
1368
|
+
});
|
|
1369
|
+
const result = await graphClient.setEntities(req);
|
|
1370
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1371
|
+
expect(result).toEqual(expected);
|
|
1372
|
+
});
|
|
1373
|
+
it('posts video entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1374
|
+
const videoEntity = {
|
|
1375
|
+
schemaVersion: '2.0',
|
|
1376
|
+
id: 'video-1',
|
|
1377
|
+
updateSequenceNumber: 1,
|
|
1378
|
+
displayName: 'Introduction to React Hooks - Team Training',
|
|
1379
|
+
url: 'https://company.video.com/watch/react-hooks-intro',
|
|
1380
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1381
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1382
|
+
permissions: {
|
|
1383
|
+
accessControls: [
|
|
1384
|
+
{
|
|
1385
|
+
principals: [
|
|
1386
|
+
{
|
|
1387
|
+
type: 'EVERYONE'
|
|
1388
|
+
}
|
|
1389
|
+
]
|
|
1390
|
+
}
|
|
1391
|
+
]
|
|
1392
|
+
},
|
|
1393
|
+
'atlassian:video': {
|
|
1394
|
+
thumbnailUrl: 'https://company.video.com/thumbnails/react-hooks-intro.jpg',
|
|
1395
|
+
embedUrl: 'https://company.video.com/embed/react-hooks-intro',
|
|
1396
|
+
durationInSeconds: 1800,
|
|
1397
|
+
width: 1920,
|
|
1398
|
+
height: 1080,
|
|
1399
|
+
commentCount: 15,
|
|
1400
|
+
textTracks: [
|
|
1401
|
+
{
|
|
1402
|
+
name: 'English Subtitles',
|
|
1403
|
+
locale: 'en-US',
|
|
1404
|
+
cues: [
|
|
1405
|
+
{
|
|
1406
|
+
id: 'cue-1',
|
|
1407
|
+
startTimeInSeconds: 0.0,
|
|
1408
|
+
endTimeInSeconds: 5.5,
|
|
1409
|
+
text: 'Welcome to our React Hooks training session.'
|
|
1410
|
+
},
|
|
1411
|
+
{
|
|
1412
|
+
id: 'cue-2',
|
|
1413
|
+
startTimeInSeconds: 5.5,
|
|
1414
|
+
endTimeInSeconds: 12.0,
|
|
1415
|
+
text: 'Today we will cover useState, useEffect, and custom hooks.'
|
|
1416
|
+
}
|
|
1417
|
+
]
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
name: 'Spanish Subtitles',
|
|
1421
|
+
locale: 'es-ES',
|
|
1422
|
+
cues: [
|
|
1423
|
+
{
|
|
1424
|
+
id: 'cue-es-1',
|
|
1425
|
+
startTimeInSeconds: 0.0,
|
|
1426
|
+
endTimeInSeconds: 5.5,
|
|
1427
|
+
text: 'Bienvenidos a nuestra sesión de entrenamiento de React Hooks.'
|
|
1428
|
+
}
|
|
1429
|
+
]
|
|
1430
|
+
}
|
|
1431
|
+
],
|
|
1432
|
+
chapters: [
|
|
1433
|
+
{
|
|
1434
|
+
startTimeInSeconds: 0,
|
|
1435
|
+
title: 'Introduction'
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
startTimeInSeconds: 300,
|
|
1439
|
+
title: 'useState Hook'
|
|
1440
|
+
},
|
|
1441
|
+
{
|
|
1442
|
+
startTimeInSeconds: 900,
|
|
1443
|
+
title: 'useEffect Hook'
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
startTimeInSeconds: 1500,
|
|
1447
|
+
title: 'Custom Hooks'
|
|
1448
|
+
}
|
|
1449
|
+
],
|
|
1450
|
+
contributors: [
|
|
1451
|
+
{
|
|
1452
|
+
user: {
|
|
1453
|
+
accountId: 'instructor-123',
|
|
1454
|
+
externalId: 'instructor-123',
|
|
1455
|
+
name: 'Sarah Johnson',
|
|
1456
|
+
userName: 'sjohnson',
|
|
1457
|
+
email: 'sarah.johnson@example.com',
|
|
1458
|
+
avatar: 'https://avatar.example.com/sarah.jpg',
|
|
1459
|
+
url: 'https://company.com/people/sarah.johnson'
|
|
1460
|
+
},
|
|
1461
|
+
interactionCount: 25
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
user: {
|
|
1465
|
+
accountId: 'participant-456',
|
|
1466
|
+
externalId: 'participant-456',
|
|
1467
|
+
name: 'Mike Chen',
|
|
1468
|
+
userName: 'mchen',
|
|
1469
|
+
email: 'mike.chen@example.com',
|
|
1470
|
+
avatar: 'https://avatar.example.com/mike.jpg',
|
|
1471
|
+
url: 'https://company.com/people/mike.chen'
|
|
1472
|
+
},
|
|
1473
|
+
interactionCount: 8
|
|
1474
|
+
}
|
|
1475
|
+
]
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
const req = { entities: [videoEntity] };
|
|
1479
|
+
const expected = { success: true, results: [{ entityId: 'video-1', success: true }] };
|
|
1480
|
+
mockFetch.mockResolvedValueOnce({
|
|
1481
|
+
ok: true,
|
|
1482
|
+
json: () => Promise.resolve(expected)
|
|
1483
|
+
});
|
|
1484
|
+
const result = await graphClient.setEntities(req);
|
|
1485
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1486
|
+
expect(result).toEqual(expected);
|
|
1487
|
+
});
|
|
1488
|
+
it('posts work item entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1489
|
+
const workItemEntity = {
|
|
1490
|
+
schemaVersion: '2.0',
|
|
1491
|
+
id: 'work-item-1',
|
|
1492
|
+
updateSequenceNumber: 1,
|
|
1493
|
+
displayName: 'Implement user authentication API endpoints',
|
|
1494
|
+
description: 'Develop secure REST API endpoints for user authentication including login, logout, password reset, and token refresh functionality with JWT implementation',
|
|
1495
|
+
url: 'https://company.jira.com/browse/AUTH-456',
|
|
1496
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1497
|
+
containerKey: {
|
|
1498
|
+
type: 'atlassian:space',
|
|
1499
|
+
value: {
|
|
1500
|
+
entityId: 'space-engineering-team-docs'
|
|
1501
|
+
}
|
|
1502
|
+
},
|
|
1503
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1504
|
+
permissions: {
|
|
1505
|
+
accessControls: [
|
|
1506
|
+
{
|
|
1507
|
+
principals: [
|
|
1508
|
+
{
|
|
1509
|
+
type: 'EVERYONE'
|
|
1510
|
+
}
|
|
1511
|
+
]
|
|
1512
|
+
}
|
|
1513
|
+
]
|
|
1514
|
+
},
|
|
1515
|
+
'atlassian:work-item': {
|
|
1516
|
+
dueDate: '2024-08-15T17:00:00.000Z',
|
|
1517
|
+
assignee: {
|
|
1518
|
+
accountId: 'dev-lead-789',
|
|
1519
|
+
externalId: 'dev-lead-789',
|
|
1520
|
+
name: 'Alex Rodriguez',
|
|
1521
|
+
userName: 'arodriguez',
|
|
1522
|
+
email: 'alex.rodriguez@example.com',
|
|
1523
|
+
avatar: 'https://avatar.example.com/alex.jpg',
|
|
1524
|
+
url: 'https://company.com/people/alex.rodriguez'
|
|
1525
|
+
},
|
|
1526
|
+
workItemProject: {
|
|
1527
|
+
id: 'auth-service-project',
|
|
1528
|
+
name: 'Authentication Service Upgrade'
|
|
1529
|
+
},
|
|
1530
|
+
collaborators: [
|
|
1531
|
+
{
|
|
1532
|
+
accountId: 'backend-dev-123',
|
|
1533
|
+
externalId: 'backend-dev-123',
|
|
1534
|
+
name: 'Sarah Chen',
|
|
1535
|
+
userName: 'schen',
|
|
1536
|
+
email: 'sarah.chen@example.com',
|
|
1537
|
+
avatar: 'https://avatar.example.com/sarah.jpg',
|
|
1538
|
+
url: 'https://company.com/people/sarah.chen'
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
accountId: 'security-expert-456',
|
|
1542
|
+
externalId: 'security-expert-456',
|
|
1543
|
+
name: 'Michael Thompson',
|
|
1544
|
+
userName: 'mthompson',
|
|
1545
|
+
email: 'michael.thompson@example.com',
|
|
1546
|
+
avatar: 'https://avatar.example.com/michael.jpg',
|
|
1547
|
+
url: 'https://company.com/people/michael.thompson'
|
|
1548
|
+
}
|
|
1549
|
+
],
|
|
1550
|
+
exceedsMaxCollaborators: false,
|
|
1551
|
+
status: 'In Progress',
|
|
1552
|
+
subtype: 'Development Task',
|
|
1553
|
+
attachments: [
|
|
1554
|
+
{
|
|
1555
|
+
url: 'https://files.example.com/auth-api-spec.pdf',
|
|
1556
|
+
thumbnailUrl: 'https://files.example.com/thumbnails/auth-api-spec.jpg',
|
|
1557
|
+
title: 'Authentication API Specification',
|
|
1558
|
+
mimeType: 'application/pdf',
|
|
1559
|
+
byteSize: 1024000
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
url: 'https://files.example.com/security-requirements.docx',
|
|
1563
|
+
thumbnailUrl: 'https://files.example.com/thumbnails/security-requirements.jpg',
|
|
1564
|
+
title: 'Security Requirements Document',
|
|
1565
|
+
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
1566
|
+
byteSize: 512000
|
|
1567
|
+
}
|
|
1568
|
+
],
|
|
1569
|
+
team: 'Backend Infrastructure Team'
|
|
1570
|
+
}
|
|
1571
|
+
};
|
|
1572
|
+
const req = { entities: [workItemEntity] };
|
|
1573
|
+
const expected = { success: true, results: [{ entityId: 'work-item-1', success: true }] };
|
|
1574
|
+
mockFetch.mockResolvedValueOnce({
|
|
1575
|
+
ok: true,
|
|
1576
|
+
json: () => Promise.resolve(expected)
|
|
1577
|
+
});
|
|
1578
|
+
const result = await graphClient.setEntities(req);
|
|
1579
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1580
|
+
expect(result).toEqual(expected);
|
|
1581
|
+
});
|
|
1582
|
+
it('posts worker entities to /api/v1/entities/bulk and returns response', async () => {
|
|
1583
|
+
const workerEntity = {
|
|
1584
|
+
schemaVersion: '2.0',
|
|
1585
|
+
id: 'worker-1',
|
|
1586
|
+
updateSequenceNumber: 1,
|
|
1587
|
+
displayName: 'Sarah Johnson - Senior Software Engineer',
|
|
1588
|
+
url: 'https://hr.example.com/employees/sarah-johnson',
|
|
1589
|
+
createdAt: '2024-07-09T14:27:37.000Z',
|
|
1590
|
+
lastUpdatedAt: '2024-07-09T14:27:37.000Z',
|
|
1591
|
+
permissions: {
|
|
1592
|
+
accessControls: [
|
|
1593
|
+
{
|
|
1594
|
+
principals: [
|
|
1595
|
+
{
|
|
1596
|
+
type: 'EVERYONE'
|
|
1597
|
+
}
|
|
1598
|
+
]
|
|
1599
|
+
}
|
|
1600
|
+
]
|
|
1601
|
+
},
|
|
1602
|
+
'atlassian:worker': {
|
|
1603
|
+
hiredAt: '2022-03-15T09:00:00.000Z',
|
|
1604
|
+
workerUser: {
|
|
1605
|
+
accountId: 'worker-sarah-123',
|
|
1606
|
+
externalId: 'emp-sarah-456',
|
|
1607
|
+
name: 'Sarah Johnson',
|
|
1608
|
+
userName: 'sjohnson',
|
|
1609
|
+
email: 'sarah.johnson@example.com',
|
|
1610
|
+
avatar: 'https://avatar.example.com/sarah.jpg',
|
|
1611
|
+
url: 'https://company.com/people/sarah.johnson',
|
|
1612
|
+
ari: 'ari:cloud:identity::user/worker-sarah-123'
|
|
1613
|
+
},
|
|
1614
|
+
customAndSensitiveData: 'Employee ID: EMP001234, Department: Engineering, Salary Grade: L5, Manager: Alex Rodriguez, Office Location: San Francisco HQ'
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
const req = { entities: [workerEntity] };
|
|
1618
|
+
const expected = { success: true, results: [{ entityId: 'worker-1', success: true }] };
|
|
1619
|
+
mockFetch.mockResolvedValueOnce({
|
|
1620
|
+
ok: true,
|
|
1621
|
+
json: () => Promise.resolve(expected)
|
|
1622
|
+
});
|
|
1623
|
+
const result = await graphClient.setEntities(req);
|
|
1624
|
+
expect(mockFetch).toHaveBeenCalledWith('/graph/connector/api/v1/entities/bulk', expect.objectContaining({ method: 'POST' }));
|
|
1625
|
+
expect(result).toEqual(expected);
|
|
1626
|
+
});
|
|
1022
1627
|
});
|