@elisra-devops/docgen-data-provider 1.139.0 → 1.140.0
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/bin/modules/TicketsDataProvider.d.ts +3 -3
- package/bin/modules/TicketsDataProvider.js +67 -44
- package/bin/modules/TicketsDataProvider.js.map +1 -1
- package/bin/tests/modules/ticketsDataProvider.historical.test.js +111 -42
- package/bin/tests/modules/ticketsDataProvider.historical.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/TicketsDataProvider.ts +78 -60
- package/src/tests/modules/ticketsDataProvider.historical.test.ts +128 -43
|
@@ -1162,73 +1162,158 @@ describe('TicketsDataProvider historical queries', () => {
|
|
|
1162
1162
|
).toBe(true);
|
|
1163
1163
|
});
|
|
1164
1164
|
|
|
1165
|
-
it('GetHistoricalQueryResults
|
|
1165
|
+
it('GetHistoricalQueryResults resolves the real Test Phase reference name from the project\'s own field list instead of guessing', async () => {
|
|
1166
1166
|
const asOfIso = '2026-02-01T00:00:00.000Z';
|
|
1167
|
-
// 205 ids -> 2 chunks (200 + 5), both dispatched with the full field list
|
|
1168
|
-
// near-simultaneously — this proves the retry is decided per-call, not
|
|
1169
|
-
// from the shared override flag, since both chunks fail before either
|
|
1170
|
-
// one sets it.
|
|
1171
|
-
const allIds = Array.from({ length: 205 }, (_, idx) => idx + 1);
|
|
1172
1167
|
|
|
1173
1168
|
(TFSServices.getItemContent as jest.Mock).mockImplementation(
|
|
1174
1169
|
async (url: string, _pat: string, method?: string, data?: any) => {
|
|
1175
|
-
if (url.includes('/_apis/wit/queries/q-
|
|
1176
|
-
return { name: '
|
|
1170
|
+
if (url.includes('/_apis/wit/queries/q-resolve-field') && url.includes('api-version=7.1')) {
|
|
1171
|
+
return { name: 'Resolve Field Q', wiql: 'SELECT [System.Id] FROM WorkItems' };
|
|
1177
1172
|
}
|
|
1178
1173
|
if (url.includes('/_apis/wit/wiql?') && method === 'post') {
|
|
1179
|
-
return { workItems:
|
|
1174
|
+
return { workItems: [{ id: 501 }] };
|
|
1175
|
+
}
|
|
1176
|
+
if (url.endsWith('/_apis/wit/fields?api-version=7.1')) {
|
|
1177
|
+
// Neither Elisra.TestPhase nor Custom.TestPhase — a third,
|
|
1178
|
+
// project-specific reference name, discovered only by friendly
|
|
1179
|
+
// name ("Test Phase").
|
|
1180
|
+
return {
|
|
1181
|
+
value: [
|
|
1182
|
+
{ name: 'Title', referenceName: 'System.Title' },
|
|
1183
|
+
{ name: 'Test Phase', referenceName: 'MyCompany.QaPhase' },
|
|
1184
|
+
],
|
|
1185
|
+
};
|
|
1180
1186
|
}
|
|
1181
1187
|
if (url.includes('/_apis/wit/workitemsbatch') && method === 'post') {
|
|
1182
1188
|
if (data?.$expand === 'Relations') {
|
|
1183
|
-
return {
|
|
1184
|
-
value: (Array.isArray(data?.ids) ? data.ids : []).map((id: number) => ({ id, relations: [] })),
|
|
1185
|
-
};
|
|
1189
|
+
return { value: [{ id: 501, relations: [] }] };
|
|
1186
1190
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1191
|
+
expect(data.fields).toEqual(expect.arrayContaining(['MyCompany.QaPhase']));
|
|
1192
|
+
expect(data.fields).not.toEqual(
|
|
1193
|
+
expect.arrayContaining(['Elisra.TestPhase', 'Custom.TestPhase']),
|
|
1194
|
+
);
|
|
1195
|
+
return {
|
|
1196
|
+
value: [
|
|
1197
|
+
{
|
|
1198
|
+
id: 501,
|
|
1199
|
+
rev: 1,
|
|
1200
|
+
fields: {
|
|
1201
|
+
'System.WorkItemType': 'Test Case',
|
|
1202
|
+
'System.Title': 'Resolved',
|
|
1203
|
+
'System.State': 'Active',
|
|
1204
|
+
'System.ChangedDate': asOfIso,
|
|
1205
|
+
'MyCompany.QaPhase': 'FAT',
|
|
1206
|
+
},
|
|
1192
1207
|
},
|
|
1193
|
-
|
|
1208
|
+
],
|
|
1209
|
+
};
|
|
1210
|
+
}
|
|
1211
|
+
throw new Error(`unexpected URL: ${url}`);
|
|
1212
|
+
},
|
|
1213
|
+
);
|
|
1214
|
+
|
|
1215
|
+
const result = await provider.GetHistoricalQueryResults('q-resolve-field', project, asOfIso);
|
|
1216
|
+
|
|
1217
|
+
expect(result.total).toBe(1);
|
|
1218
|
+
const fieldsListCalls = (TFSServices.getItemContent as jest.Mock).mock.calls.filter((call) =>
|
|
1219
|
+
String(call[0]).endsWith('/_apis/wit/fields?api-version=7.1'),
|
|
1220
|
+
);
|
|
1221
|
+
expect(fieldsListCalls).toHaveLength(1);
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
it('GetHistoricalQueryResults reuses the resolved field across baseline and compareTo without re-querying fields', async () => {
|
|
1225
|
+
const baselineIso = '2026-02-20T00:00:00.000Z';
|
|
1226
|
+
const compareIso = '2026-02-25T00:00:00.000Z';
|
|
1227
|
+
let fieldsListCallCount = 0;
|
|
1228
|
+
|
|
1229
|
+
(TFSServices.getItemContent as jest.Mock).mockImplementation(
|
|
1230
|
+
async (url: string, _pat: string, method?: string, data?: any) => {
|
|
1231
|
+
if (url.includes('/_apis/wit/queries/q-cache-field') && url.includes('api-version=7.1')) {
|
|
1232
|
+
return { name: 'Cache Field Q', wiql: 'SELECT [System.Id] FROM WorkItems' };
|
|
1233
|
+
}
|
|
1234
|
+
if (url.includes('/_apis/wit/wiql?') && method === 'post') {
|
|
1235
|
+
return { workItems: [{ id: 601 }] };
|
|
1236
|
+
}
|
|
1237
|
+
if (url.endsWith('/_apis/wit/fields?api-version=7.1')) {
|
|
1238
|
+
fieldsListCallCount += 1;
|
|
1239
|
+
return { value: [{ name: 'Test Phase', referenceName: 'Custom.TestPhase' }] };
|
|
1240
|
+
}
|
|
1241
|
+
if (url.includes('/_apis/wit/workitemsbatch') && method === 'post') {
|
|
1242
|
+
if (data?.$expand === 'Relations') {
|
|
1243
|
+
return { value: [{ id: 601, relations: [] }] };
|
|
1194
1244
|
}
|
|
1195
|
-
// Custom.TestPhase is the real field on this project and must
|
|
1196
|
-
// still be requested — only the unrecognized alias should be
|
|
1197
|
-
// dropped, not every optional field.
|
|
1198
|
-
expect(data.fields).toEqual(expect.arrayContaining(['Custom.TestPhase']));
|
|
1199
|
-
expect(data.fields).not.toEqual(expect.arrayContaining(['Elisra.TestPhase']));
|
|
1200
1245
|
return {
|
|
1201
|
-
value:
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1246
|
+
value: [
|
|
1247
|
+
{
|
|
1248
|
+
id: 601,
|
|
1249
|
+
rev: 1,
|
|
1250
|
+
fields: {
|
|
1251
|
+
'System.WorkItemType': 'Test Case',
|
|
1252
|
+
'System.Title': 'Cached',
|
|
1253
|
+
'System.State': 'Active',
|
|
1254
|
+
'System.ChangedDate': data.asOf,
|
|
1255
|
+
},
|
|
1210
1256
|
},
|
|
1211
|
-
|
|
1257
|
+
],
|
|
1212
1258
|
};
|
|
1213
1259
|
}
|
|
1214
1260
|
throw new Error(`unexpected URL: ${url}`);
|
|
1215
1261
|
},
|
|
1216
1262
|
);
|
|
1217
1263
|
|
|
1218
|
-
|
|
1264
|
+
await provider.CompareHistoricalQueryResults('q-cache-field', project, baselineIso, compareIso);
|
|
1219
1265
|
|
|
1220
|
-
//
|
|
1221
|
-
//
|
|
1222
|
-
expect(
|
|
1223
|
-
|
|
1224
|
-
|
|
1266
|
+
// Baseline and compareTo run concurrently against the same provider
|
|
1267
|
+
// instance — the field list is fetched once, not once per snapshot.
|
|
1268
|
+
expect(fieldsListCallCount).toBe(1);
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
it('GetHistoricalQueryResults omits Test Phase entirely when the project defines neither known name, without failing the batch', async () => {
|
|
1272
|
+
const asOfIso = '2026-03-01T00:00:00.000Z';
|
|
1273
|
+
|
|
1274
|
+
(TFSServices.getItemContent as jest.Mock).mockImplementation(
|
|
1275
|
+
async (url: string, _pat: string, method?: string, data?: any) => {
|
|
1276
|
+
if (url.includes('/_apis/wit/queries/q-no-field') && url.includes('api-version=7.1')) {
|
|
1277
|
+
return { name: 'No Field Q', wiql: 'SELECT [System.Id] FROM WorkItems' };
|
|
1278
|
+
}
|
|
1279
|
+
if (url.includes('/_apis/wit/wiql?') && method === 'post') {
|
|
1280
|
+
return { workItems: [{ id: 701 }] };
|
|
1281
|
+
}
|
|
1282
|
+
if (url.endsWith('/_apis/wit/fields?api-version=7.1')) {
|
|
1283
|
+
return { value: [{ name: 'Title', referenceName: 'System.Title' }] };
|
|
1284
|
+
}
|
|
1285
|
+
if (url.includes('/_apis/wit/workitemsbatch') && method === 'post') {
|
|
1286
|
+
if (data?.$expand === 'Relations') {
|
|
1287
|
+
return { value: [{ id: 701, relations: [] }] };
|
|
1288
|
+
}
|
|
1289
|
+
expect(data.fields).not.toEqual(
|
|
1290
|
+
expect.arrayContaining(['Elisra.TestPhase', 'Custom.TestPhase']),
|
|
1291
|
+
);
|
|
1292
|
+
return {
|
|
1293
|
+
value: [
|
|
1294
|
+
{
|
|
1295
|
+
id: 701,
|
|
1296
|
+
rev: 1,
|
|
1297
|
+
fields: {
|
|
1298
|
+
'System.WorkItemType': 'Bug',
|
|
1299
|
+
'System.Title': 'No test phase field',
|
|
1300
|
+
'System.State': 'Active',
|
|
1301
|
+
'System.ChangedDate': asOfIso,
|
|
1302
|
+
},
|
|
1303
|
+
},
|
|
1304
|
+
],
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
throw new Error(`unexpected URL: ${url}`);
|
|
1308
|
+
},
|
|
1225
1309
|
);
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1310
|
+
|
|
1311
|
+
const result = await provider.GetHistoricalQueryResults('q-no-field', project, asOfIso);
|
|
1312
|
+
|
|
1313
|
+
expect(result.total).toBe(1);
|
|
1229
1314
|
expect(
|
|
1230
1315
|
(logger.warn as jest.Mock).mock.calls.some((call) =>
|
|
1231
|
-
String(call[0]).includes("
|
|
1316
|
+
String(call[0]).includes("no Test Phase field defined for project"),
|
|
1232
1317
|
),
|
|
1233
1318
|
).toBe(true);
|
|
1234
1319
|
});
|