@elisra-devops/docgen-data-provider 1.72.0 → 1.74.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/ResultDataProvider.d.ts +38 -0
- package/bin/modules/ResultDataProvider.js +688 -7
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +438 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +850 -7
- package/src/tests/modules/ResultDataProvider.test.ts +555 -0
|
@@ -1074,6 +1074,323 @@ describe('ResultDataProvider', () => {
|
|
|
1074
1074
|
});
|
|
1075
1075
|
});
|
|
1076
1076
|
|
|
1077
|
+
describe('getMewpL2CoverageFlatResults', () => {
|
|
1078
|
+
it('should support query-mode requirement scope for MEWP coverage', async () => {
|
|
1079
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1080
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1081
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
1082
|
+
{
|
|
1083
|
+
testPointsItems: [{ testCaseId: 101, lastRunId: 10, lastResultId: 20, testCaseName: 'TC 101' }],
|
|
1084
|
+
testCasesItems: [
|
|
1085
|
+
{
|
|
1086
|
+
workItem: {
|
|
1087
|
+
id: 101,
|
|
1088
|
+
workItemFields: [{ key: 'System.Title', value: 'TC 101' }],
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
],
|
|
1092
|
+
},
|
|
1093
|
+
]);
|
|
1094
|
+
jest.spyOn(resultDataProvider as any, 'fetchMewpRequirementTypeNames').mockResolvedValueOnce([
|
|
1095
|
+
'Requirement',
|
|
1096
|
+
]);
|
|
1097
|
+
jest.spyOn(resultDataProvider as any, 'fetchWorkItemsByIds').mockResolvedValueOnce([
|
|
1098
|
+
{
|
|
1099
|
+
id: 9001,
|
|
1100
|
+
fields: {
|
|
1101
|
+
'System.WorkItemType': 'Requirement',
|
|
1102
|
+
'System.Title': 'Requirement from query',
|
|
1103
|
+
'Custom.CustomerId': 'SR3001',
|
|
1104
|
+
'System.AreaPath': 'MEWP\\IL',
|
|
1105
|
+
},
|
|
1106
|
+
relations: [
|
|
1107
|
+
{
|
|
1108
|
+
rel: 'Microsoft.VSTS.Common.TestedBy-Forward',
|
|
1109
|
+
url: 'https://dev.azure.com/org/_apis/wit/workItems/101',
|
|
1110
|
+
},
|
|
1111
|
+
],
|
|
1112
|
+
},
|
|
1113
|
+
]);
|
|
1114
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
1115
|
+
{
|
|
1116
|
+
testCaseId: 101,
|
|
1117
|
+
testCase: { id: 101, name: 'TC 101' },
|
|
1118
|
+
iteration: {
|
|
1119
|
+
actionResults: [{ action: 'Validate SR3001', expected: '', outcome: 'Passed' }],
|
|
1120
|
+
},
|
|
1121
|
+
},
|
|
1122
|
+
]);
|
|
1123
|
+
|
|
1124
|
+
const TicketsProviderMock: any = require('../../modules/TicketsDataProvider').default;
|
|
1125
|
+
TicketsProviderMock.mockImplementationOnce(() => ({
|
|
1126
|
+
GetQueryResultsFromWiql: jest.fn().mockResolvedValue({
|
|
1127
|
+
fetchedWorkItems: [
|
|
1128
|
+
{
|
|
1129
|
+
id: 9001,
|
|
1130
|
+
fields: {
|
|
1131
|
+
'System.WorkItemType': 'Requirement',
|
|
1132
|
+
'System.Title': 'Requirement from query',
|
|
1133
|
+
'Custom.CustomerId': 'SR3001',
|
|
1134
|
+
'System.AreaPath': 'MEWP\\IL',
|
|
1135
|
+
},
|
|
1136
|
+
},
|
|
1137
|
+
],
|
|
1138
|
+
}),
|
|
1139
|
+
}));
|
|
1140
|
+
|
|
1141
|
+
const result = await (resultDataProvider as any).getMewpL2CoverageFlatResults(
|
|
1142
|
+
'123',
|
|
1143
|
+
mockProjectName,
|
|
1144
|
+
[1],
|
|
1145
|
+
{
|
|
1146
|
+
linkedQueryMode: 'query',
|
|
1147
|
+
testAssociatedQuery: { wiql: { href: 'https://example.com/wiql' } },
|
|
1148
|
+
}
|
|
1149
|
+
);
|
|
1150
|
+
|
|
1151
|
+
const row = result.rows.find((item: any) => item['Customer ID'] === 'SR3001');
|
|
1152
|
+
expect(row).toEqual(
|
|
1153
|
+
expect.objectContaining({
|
|
1154
|
+
'Title (Customer name)': 'Requirement from query',
|
|
1155
|
+
'Responsibility - SAPWBS (ESUK/IL)': 'IL',
|
|
1156
|
+
'Test case id': 101,
|
|
1157
|
+
'Test case title': 'TC 101',
|
|
1158
|
+
'Number of passed steps': 1,
|
|
1159
|
+
'Number of failed steps': 0,
|
|
1160
|
+
'Number of not run tests': 0,
|
|
1161
|
+
})
|
|
1162
|
+
);
|
|
1163
|
+
|
|
1164
|
+
expect(TicketsProviderMock).toHaveBeenCalled();
|
|
1165
|
+
const instance = TicketsProviderMock.mock.results[0].value;
|
|
1166
|
+
expect(instance.GetQueryResultsFromWiql).toHaveBeenCalledWith(
|
|
1167
|
+
'https://example.com/wiql',
|
|
1168
|
+
true,
|
|
1169
|
+
expect.any(Map)
|
|
1170
|
+
);
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
it('should map SR ids from steps and output requirement-test-case coverage rows', async () => {
|
|
1174
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1175
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1176
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
1177
|
+
{
|
|
1178
|
+
testPointsItems: [
|
|
1179
|
+
{ testCaseId: 101, lastRunId: 11, lastResultId: 22, testCaseName: 'TC 101' },
|
|
1180
|
+
{ testCaseId: 102, lastRunId: 0, lastResultId: 0, testCaseName: 'TC 102' },
|
|
1181
|
+
],
|
|
1182
|
+
testCasesItems: [
|
|
1183
|
+
{
|
|
1184
|
+
workItem: {
|
|
1185
|
+
id: 102,
|
|
1186
|
+
workItemFields: [{ key: 'Steps', value: '<steps></steps>' }],
|
|
1187
|
+
},
|
|
1188
|
+
},
|
|
1189
|
+
],
|
|
1190
|
+
},
|
|
1191
|
+
]);
|
|
1192
|
+
jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1193
|
+
{
|
|
1194
|
+
workItemId: 5001,
|
|
1195
|
+
requirementId: 'SR1001',
|
|
1196
|
+
title: 'Covered requirement',
|
|
1197
|
+
responsibility: 'ESUK',
|
|
1198
|
+
linkedTestCaseIds: [101],
|
|
1199
|
+
},
|
|
1200
|
+
{
|
|
1201
|
+
workItemId: 5002,
|
|
1202
|
+
requirementId: 'SR1002',
|
|
1203
|
+
title: 'Referenced from non-linked step text',
|
|
1204
|
+
responsibility: 'IL',
|
|
1205
|
+
linkedTestCaseIds: [],
|
|
1206
|
+
},
|
|
1207
|
+
{
|
|
1208
|
+
workItemId: 5003,
|
|
1209
|
+
requirementId: 'SR1003',
|
|
1210
|
+
title: 'Not covered by any test case',
|
|
1211
|
+
responsibility: 'IL',
|
|
1212
|
+
linkedTestCaseIds: [],
|
|
1213
|
+
},
|
|
1214
|
+
]);
|
|
1215
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
1216
|
+
{
|
|
1217
|
+
testCaseId: 101,
|
|
1218
|
+
testCase: { id: 101, name: 'TC 101' },
|
|
1219
|
+
iteration: {
|
|
1220
|
+
actionResults: [
|
|
1221
|
+
{
|
|
1222
|
+
action: 'Validate <b>S</b><b>R</b> 1 0 0 1 happy path',
|
|
1223
|
+
expected: '',
|
|
1224
|
+
outcome: 'Passed',
|
|
1225
|
+
},
|
|
1226
|
+
{ action: 'Validate SR1001 failed flow', expected: ' ', outcome: 'Failed' },
|
|
1227
|
+
{ action: '', expected: 'Pending S R 1 0 0 1 scenario', outcome: 'Unspecified' },
|
|
1228
|
+
],
|
|
1229
|
+
},
|
|
1230
|
+
},
|
|
1231
|
+
{
|
|
1232
|
+
testCaseId: 102,
|
|
1233
|
+
testCase: { id: 102, name: 'TC 102' },
|
|
1234
|
+
iteration: undefined,
|
|
1235
|
+
},
|
|
1236
|
+
]);
|
|
1237
|
+
jest
|
|
1238
|
+
.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps')
|
|
1239
|
+
.mockResolvedValueOnce([
|
|
1240
|
+
{
|
|
1241
|
+
stepId: '1',
|
|
1242
|
+
stepPosition: '1',
|
|
1243
|
+
action: 'Definition contains SR1002',
|
|
1244
|
+
expected: '',
|
|
1245
|
+
isSharedStepTitle: false,
|
|
1246
|
+
},
|
|
1247
|
+
]);
|
|
1248
|
+
|
|
1249
|
+
const result = await (resultDataProvider as any).getMewpL2CoverageFlatResults(
|
|
1250
|
+
'123',
|
|
1251
|
+
mockProjectName,
|
|
1252
|
+
[1]
|
|
1253
|
+
);
|
|
1254
|
+
|
|
1255
|
+
expect(result).toEqual(
|
|
1256
|
+
expect.objectContaining({
|
|
1257
|
+
sheetName: expect.stringContaining('MEWP L2 Coverage'),
|
|
1258
|
+
columnOrder: expect.arrayContaining(['Customer ID', 'Test case id', 'Number of not run tests']),
|
|
1259
|
+
})
|
|
1260
|
+
);
|
|
1261
|
+
|
|
1262
|
+
const covered = result.rows.find(
|
|
1263
|
+
(row: any) => row['Customer ID'] === 'SR1001' && row['Test case id'] === 101
|
|
1264
|
+
);
|
|
1265
|
+
const inferredByStepText = result.rows.find(
|
|
1266
|
+
(row: any) => row['Customer ID'] === 'SR1002' && row['Test case id'] === 102
|
|
1267
|
+
);
|
|
1268
|
+
const uncovered = result.rows.find(
|
|
1269
|
+
(row: any) =>
|
|
1270
|
+
row['Customer ID'] === 'SR1003' &&
|
|
1271
|
+
(row['Test case id'] === '' || row['Test case id'] === undefined || row['Test case id'] === null)
|
|
1272
|
+
);
|
|
1273
|
+
|
|
1274
|
+
expect(covered).toEqual(
|
|
1275
|
+
expect.objectContaining({
|
|
1276
|
+
'Title (Customer name)': 'Covered requirement',
|
|
1277
|
+
'Responsibility - SAPWBS (ESUK/IL)': 'ESUK',
|
|
1278
|
+
'Test case title': 'TC 101',
|
|
1279
|
+
'Number of passed steps': 1,
|
|
1280
|
+
'Number of failed steps': 1,
|
|
1281
|
+
'Number of not run tests': 1,
|
|
1282
|
+
})
|
|
1283
|
+
);
|
|
1284
|
+
expect(inferredByStepText).toEqual(
|
|
1285
|
+
expect.objectContaining({
|
|
1286
|
+
'Title (Customer name)': 'Referenced from non-linked step text',
|
|
1287
|
+
'Responsibility - SAPWBS (ESUK/IL)': 'IL',
|
|
1288
|
+
'Test case title': 'TC 102',
|
|
1289
|
+
'Number of passed steps': 0,
|
|
1290
|
+
'Number of failed steps': 0,
|
|
1291
|
+
'Number of not run tests': 1,
|
|
1292
|
+
})
|
|
1293
|
+
);
|
|
1294
|
+
expect(uncovered).toEqual(
|
|
1295
|
+
expect.objectContaining({
|
|
1296
|
+
'Title (Customer name)': 'Not covered by any test case',
|
|
1297
|
+
'Responsibility - SAPWBS (ESUK/IL)': 'IL',
|
|
1298
|
+
'Test case title': '',
|
|
1299
|
+
'Number of passed steps': 0,
|
|
1300
|
+
'Number of failed steps': 0,
|
|
1301
|
+
'Number of not run tests': 0,
|
|
1302
|
+
})
|
|
1303
|
+
);
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
it('should extract SR ids from HTML/spacing and return unique ids per step text', () => {
|
|
1307
|
+
const text =
|
|
1308
|
+
'A: <b>S</b><b>R</b> 0 0 0 1; B: SR0002; C: S R 0 0 0 3; D: SR0002; E: <b>SR</b>0004';
|
|
1309
|
+
const codes = (resultDataProvider as any).extractRequirementCodesFromText(text);
|
|
1310
|
+
expect([...codes].sort()).toEqual(['SR1', 'SR2', 'SR3', 'SR4']);
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
it('should not backfill definition steps as not-run when a real run exists but has no action results', async () => {
|
|
1314
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan A');
|
|
1315
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([{ testSuiteId: 1 }]);
|
|
1316
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce([
|
|
1317
|
+
{
|
|
1318
|
+
testPointsItems: [{ testCaseId: 101, lastRunId: 88, lastResultId: 99, testCaseName: 'TC 101' }],
|
|
1319
|
+
testCasesItems: [
|
|
1320
|
+
{
|
|
1321
|
+
workItem: {
|
|
1322
|
+
id: 101,
|
|
1323
|
+
workItemFields: [{ key: 'Steps', value: '<steps></steps>' }],
|
|
1324
|
+
},
|
|
1325
|
+
},
|
|
1326
|
+
],
|
|
1327
|
+
},
|
|
1328
|
+
]);
|
|
1329
|
+
jest.spyOn(resultDataProvider as any, 'fetchMewpL2Requirements').mockResolvedValueOnce([
|
|
1330
|
+
{
|
|
1331
|
+
workItemId: 7001,
|
|
1332
|
+
requirementId: 'SR2001',
|
|
1333
|
+
title: 'Has run but no actions',
|
|
1334
|
+
responsibility: 'ESUK',
|
|
1335
|
+
linkedTestCaseIds: [101],
|
|
1336
|
+
},
|
|
1337
|
+
]);
|
|
1338
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
1339
|
+
{
|
|
1340
|
+
testCaseId: 101,
|
|
1341
|
+
lastRunId: 88,
|
|
1342
|
+
lastResultId: 99,
|
|
1343
|
+
iteration: {
|
|
1344
|
+
actionResults: [],
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
]);
|
|
1348
|
+
|
|
1349
|
+
const parseSpy = jest
|
|
1350
|
+
.spyOn((resultDataProvider as any).testStepParserHelper, 'parseTestSteps')
|
|
1351
|
+
.mockResolvedValueOnce([
|
|
1352
|
+
{
|
|
1353
|
+
stepId: '1',
|
|
1354
|
+
stepPosition: '1',
|
|
1355
|
+
action: 'SR2001 from definition',
|
|
1356
|
+
expected: '',
|
|
1357
|
+
isSharedStepTitle: false,
|
|
1358
|
+
},
|
|
1359
|
+
]);
|
|
1360
|
+
|
|
1361
|
+
const result = await (resultDataProvider as any).getMewpL2CoverageFlatResults(
|
|
1362
|
+
'123',
|
|
1363
|
+
mockProjectName,
|
|
1364
|
+
[1]
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
const row = result.rows.find(
|
|
1368
|
+
(item: any) => item['Customer ID'] === 'SR2001' && item['Test case id'] === 101
|
|
1369
|
+
);
|
|
1370
|
+
expect(parseSpy).not.toHaveBeenCalled();
|
|
1371
|
+
expect(row).toEqual(
|
|
1372
|
+
expect.objectContaining({
|
|
1373
|
+
'Number of passed steps': 0,
|
|
1374
|
+
'Number of failed steps': 0,
|
|
1375
|
+
'Number of not run tests': 0,
|
|
1376
|
+
})
|
|
1377
|
+
);
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
it('should not infer requirement id from unrelated SR text in non-identifier fields', () => {
|
|
1381
|
+
const requirementId = (resultDataProvider as any).extractMewpRequirementIdentifier(
|
|
1382
|
+
{
|
|
1383
|
+
'System.Description': 'random text with SR9999 that is unrelated',
|
|
1384
|
+
'Custom.CustomerId': 'customer id unknown',
|
|
1385
|
+
'System.Title': 'Requirement without explicit SR code',
|
|
1386
|
+
},
|
|
1387
|
+
4321
|
|
1388
|
+
);
|
|
1389
|
+
|
|
1390
|
+
expect(requirementId).toBe('4321');
|
|
1391
|
+
});
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1077
1394
|
describe('fetchResultDataForTestReporter (runResultField switch)', () => {
|
|
1078
1395
|
it('should populate requested runResultField values including testCaseResult URL branches', async () => {
|
|
1079
1396
|
jest
|
|
@@ -2586,6 +2903,244 @@ describe('ResultDataProvider', () => {
|
|
|
2586
2903
|
expect.objectContaining({ stepIdentifier: '2', action: 'A2', isSharedStepTitle: true })
|
|
2587
2904
|
);
|
|
2588
2905
|
});
|
|
2906
|
+
|
|
2907
|
+
it('should fall back to parsed test steps when actionResults are missing for latest run', async () => {
|
|
2908
|
+
const point = { testCaseId: 1, lastRunId: 10, lastResultId: 20 };
|
|
2909
|
+
const fetchResultMethod = jest.fn().mockResolvedValue({
|
|
2910
|
+
testCase: { id: 1, name: 'TC' },
|
|
2911
|
+
stepsResultXml: '<steps></steps>',
|
|
2912
|
+
iterationDetails: [{}],
|
|
2913
|
+
});
|
|
2914
|
+
|
|
2915
|
+
const createResponseObject = (resultData: any) => ({ iteration: resultData.iterationDetails[0] });
|
|
2916
|
+
|
|
2917
|
+
const helper = (resultDataProvider as any).testStepParserHelper;
|
|
2918
|
+
helper.parseTestSteps.mockResolvedValueOnce([
|
|
2919
|
+
{ stepId: 172, stepPosition: '1', action: 'Step 1', expected: 'Expected 1', isSharedStepTitle: false },
|
|
2920
|
+
{ stepId: 173, stepPosition: '2', action: 'Step 2', expected: 'Expected 2', isSharedStepTitle: false },
|
|
2921
|
+
]);
|
|
2922
|
+
|
|
2923
|
+
const res = await (resultDataProvider as any).fetchResultDataBase(
|
|
2924
|
+
mockProjectName,
|
|
2925
|
+
'suite1',
|
|
2926
|
+
point,
|
|
2927
|
+
fetchResultMethod,
|
|
2928
|
+
createResponseObject,
|
|
2929
|
+
[]
|
|
2930
|
+
);
|
|
2931
|
+
|
|
2932
|
+
const actionResults = res.iteration.actionResults;
|
|
2933
|
+
expect(actionResults).toHaveLength(2);
|
|
2934
|
+
expect(actionResults[0]).toEqual(
|
|
2935
|
+
expect.objectContaining({
|
|
2936
|
+
stepIdentifier: '172',
|
|
2937
|
+
stepPosition: '1',
|
|
2938
|
+
action: 'Step 1',
|
|
2939
|
+
expected: 'Expected 1',
|
|
2940
|
+
outcome: 'Unspecified',
|
|
2941
|
+
})
|
|
2942
|
+
);
|
|
2943
|
+
expect(actionResults[1]).toEqual(
|
|
2944
|
+
expect.objectContaining({
|
|
2945
|
+
stepIdentifier: '173',
|
|
2946
|
+
stepPosition: '2',
|
|
2947
|
+
action: 'Step 2',
|
|
2948
|
+
expected: 'Expected 2',
|
|
2949
|
+
outcome: 'Unspecified',
|
|
2950
|
+
})
|
|
2951
|
+
);
|
|
2952
|
+
});
|
|
2953
|
+
|
|
2954
|
+
it('should create synthetic iteration and fall back to parsed test steps when iterationDetails are missing', async () => {
|
|
2955
|
+
const point = { testCaseId: 1, lastRunId: 10, lastResultId: 20 };
|
|
2956
|
+
const fetchResultMethod = jest.fn().mockResolvedValue({
|
|
2957
|
+
testCase: { id: 1, name: 'TC' },
|
|
2958
|
+
stepsResultXml: '<steps></steps>',
|
|
2959
|
+
iterationDetails: [],
|
|
2960
|
+
});
|
|
2961
|
+
|
|
2962
|
+
const createResponseObject = (resultData: any) => ({ iteration: resultData.iterationDetails[0] });
|
|
2963
|
+
|
|
2964
|
+
const helper = (resultDataProvider as any).testStepParserHelper;
|
|
2965
|
+
helper.parseTestSteps.mockResolvedValueOnce([
|
|
2966
|
+
{ stepId: 301, stepPosition: '1', action: 'S1', expected: 'E1', isSharedStepTitle: false },
|
|
2967
|
+
]);
|
|
2968
|
+
|
|
2969
|
+
const res = await (resultDataProvider as any).fetchResultDataBase(
|
|
2970
|
+
mockProjectName,
|
|
2971
|
+
'suite1',
|
|
2972
|
+
point,
|
|
2973
|
+
fetchResultMethod,
|
|
2974
|
+
createResponseObject,
|
|
2975
|
+
[]
|
|
2976
|
+
);
|
|
2977
|
+
|
|
2978
|
+
expect(res.iteration).toBeDefined();
|
|
2979
|
+
expect(res.iteration.actionResults).toHaveLength(1);
|
|
2980
|
+
expect(res.iteration.actionResults[0]).toEqual(
|
|
2981
|
+
expect.objectContaining({
|
|
2982
|
+
stepIdentifier: '301',
|
|
2983
|
+
stepPosition: '1',
|
|
2984
|
+
action: 'S1',
|
|
2985
|
+
expected: 'E1',
|
|
2986
|
+
outcome: 'Unspecified',
|
|
2987
|
+
})
|
|
2988
|
+
);
|
|
2989
|
+
});
|
|
2990
|
+
|
|
2991
|
+
it('should fall back to parsed test steps when actionResults is an empty array', async () => {
|
|
2992
|
+
const point = { testCaseId: 1, lastRunId: 10, lastResultId: 20 };
|
|
2993
|
+
const fetchResultMethod = jest.fn().mockResolvedValue({
|
|
2994
|
+
testCase: { id: 1, name: 'TC' },
|
|
2995
|
+
stepsResultXml: '<steps></steps>',
|
|
2996
|
+
iterationDetails: [{ actionResults: [] }],
|
|
2997
|
+
});
|
|
2998
|
+
|
|
2999
|
+
const createResponseObject = (resultData: any) => ({ iteration: resultData.iterationDetails[0] });
|
|
3000
|
+
|
|
3001
|
+
const helper = (resultDataProvider as any).testStepParserHelper;
|
|
3002
|
+
helper.parseTestSteps.mockResolvedValueOnce([
|
|
3003
|
+
{ stepId: 11, stepPosition: '1', action: 'A1', expected: 'E1', isSharedStepTitle: false },
|
|
3004
|
+
{ stepId: 22, stepPosition: '2', action: 'A2', expected: 'E2', isSharedStepTitle: false },
|
|
3005
|
+
]);
|
|
3006
|
+
|
|
3007
|
+
const res = await (resultDataProvider as any).fetchResultDataBase(
|
|
3008
|
+
mockProjectName,
|
|
3009
|
+
'suite1',
|
|
3010
|
+
point,
|
|
3011
|
+
fetchResultMethod,
|
|
3012
|
+
createResponseObject,
|
|
3013
|
+
[]
|
|
3014
|
+
);
|
|
3015
|
+
|
|
3016
|
+
expect(helper.parseTestSteps).toHaveBeenCalledTimes(1);
|
|
3017
|
+
expect(res.iteration.actionResults).toHaveLength(2);
|
|
3018
|
+
expect(res.iteration.actionResults[0]).toEqual(
|
|
3019
|
+
expect.objectContaining({
|
|
3020
|
+
stepIdentifier: '11',
|
|
3021
|
+
stepPosition: '1',
|
|
3022
|
+
action: 'A1',
|
|
3023
|
+
expected: 'E1',
|
|
3024
|
+
outcome: 'Unspecified',
|
|
3025
|
+
})
|
|
3026
|
+
);
|
|
3027
|
+
expect(res.iteration.actionResults[1]).toEqual(
|
|
3028
|
+
expect.objectContaining({
|
|
3029
|
+
stepIdentifier: '22',
|
|
3030
|
+
stepPosition: '2',
|
|
3031
|
+
action: 'A2',
|
|
3032
|
+
expected: 'E2',
|
|
3033
|
+
outcome: 'Unspecified',
|
|
3034
|
+
})
|
|
3035
|
+
);
|
|
3036
|
+
});
|
|
3037
|
+
});
|
|
3038
|
+
|
|
3039
|
+
describe('getTestReporterFlatResults', () => {
|
|
3040
|
+
it('should return flat rows with logical step numbering for fallback-generated action results', async () => {
|
|
3041
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestPlanName').mockResolvedValueOnce('Plan 12');
|
|
3042
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestSuites').mockResolvedValueOnce([
|
|
3043
|
+
{
|
|
3044
|
+
testSuiteId: 200,
|
|
3045
|
+
suiteId: 200,
|
|
3046
|
+
suiteName: 'suite 2.1',
|
|
3047
|
+
parentSuiteId: 100,
|
|
3048
|
+
parentSuiteName: 'Rel2',
|
|
3049
|
+
suitePath: 'Root/Rel2/suite 2.1',
|
|
3050
|
+
testGroupName: 'suite 2.1',
|
|
3051
|
+
},
|
|
3052
|
+
]);
|
|
3053
|
+
|
|
3054
|
+
const testData = [
|
|
3055
|
+
{
|
|
3056
|
+
testSuiteId: 200,
|
|
3057
|
+
suiteId: 200,
|
|
3058
|
+
suiteName: 'suite 2.1',
|
|
3059
|
+
parentSuiteId: 100,
|
|
3060
|
+
parentSuiteName: 'Rel2',
|
|
3061
|
+
suitePath: 'Root/Rel2/suite 2.1',
|
|
3062
|
+
testGroupName: 'suite 2.1',
|
|
3063
|
+
testPointsItems: [
|
|
3064
|
+
{
|
|
3065
|
+
testCaseId: 17,
|
|
3066
|
+
testCaseName: 'TC 17',
|
|
3067
|
+
outcome: 'Unspecified',
|
|
3068
|
+
lastRunId: 99,
|
|
3069
|
+
lastResultId: 88,
|
|
3070
|
+
testPointId: 501,
|
|
3071
|
+
lastResultDetails: {
|
|
3072
|
+
dateCompleted: '2026-02-01T10:00:00.000Z',
|
|
3073
|
+
outcome: 'Unspecified',
|
|
3074
|
+
runBy: { displayName: 'tester user' },
|
|
3075
|
+
},
|
|
3076
|
+
},
|
|
3077
|
+
],
|
|
3078
|
+
testCasesItems: [
|
|
3079
|
+
{
|
|
3080
|
+
workItem: {
|
|
3081
|
+
id: 17,
|
|
3082
|
+
workItemFields: [{ key: 'Steps', value: '<steps></steps>' }],
|
|
3083
|
+
},
|
|
3084
|
+
},
|
|
3085
|
+
],
|
|
3086
|
+
},
|
|
3087
|
+
];
|
|
3088
|
+
jest.spyOn(resultDataProvider as any, 'fetchTestData').mockResolvedValueOnce(testData);
|
|
3089
|
+
jest.spyOn(resultDataProvider as any, 'fetchAllResultDataTestReporter').mockResolvedValueOnce([
|
|
3090
|
+
{
|
|
3091
|
+
testCaseId: 17,
|
|
3092
|
+
lastRunId: 99,
|
|
3093
|
+
lastResultId: 88,
|
|
3094
|
+
executionDate: '2026-02-01T10:00:00.000Z',
|
|
3095
|
+
testCaseResult: { resultMessage: '' },
|
|
3096
|
+
customFields: { 'Custom.SubSystem': 'SYS' },
|
|
3097
|
+
runBy: 'tester user',
|
|
3098
|
+
iteration: {
|
|
3099
|
+
actionResults: [
|
|
3100
|
+
{
|
|
3101
|
+
stepIdentifier: '172',
|
|
3102
|
+
stepPosition: '1',
|
|
3103
|
+
actionPath: '1',
|
|
3104
|
+
action: 'fallback action',
|
|
3105
|
+
expected: 'fallback expected',
|
|
3106
|
+
outcome: 'Unspecified',
|
|
3107
|
+
errorMessage: '',
|
|
3108
|
+
isSharedStepTitle: false,
|
|
3109
|
+
},
|
|
3110
|
+
],
|
|
3111
|
+
},
|
|
3112
|
+
},
|
|
3113
|
+
]);
|
|
3114
|
+
|
|
3115
|
+
const result = await resultDataProvider.getTestReporterFlatResults(
|
|
3116
|
+
mockTestPlanId,
|
|
3117
|
+
mockProjectName,
|
|
3118
|
+
undefined,
|
|
3119
|
+
[],
|
|
3120
|
+
false
|
|
3121
|
+
);
|
|
3122
|
+
|
|
3123
|
+
expect(result.planId).toBe(mockTestPlanId);
|
|
3124
|
+
expect(result.planName).toBe('Plan 12');
|
|
3125
|
+
expect(result.rows).toHaveLength(1);
|
|
3126
|
+
expect(result.rows[0]).toEqual(
|
|
3127
|
+
expect.objectContaining({
|
|
3128
|
+
planId: mockTestPlanId,
|
|
3129
|
+
planName: 'Plan 12',
|
|
3130
|
+
suiteId: 200,
|
|
3131
|
+
suiteName: 'suite 2.1',
|
|
3132
|
+
parentSuiteId: 100,
|
|
3133
|
+
parentSuiteName: 'Rel2',
|
|
3134
|
+
suitePath: 'Root/Rel2/suite 2.1',
|
|
3135
|
+
testCaseId: 17,
|
|
3136
|
+
testCaseName: 'TC 17',
|
|
3137
|
+
testRunId: 99,
|
|
3138
|
+
testPointId: 501,
|
|
3139
|
+
stepOutcome: 'Unspecified',
|
|
3140
|
+
stepStepIdentifier: '1',
|
|
3141
|
+
})
|
|
3142
|
+
);
|
|
3143
|
+
});
|
|
2589
3144
|
});
|
|
2590
3145
|
|
|
2591
3146
|
describe('getCombinedResultsSummary - appendix branches', () => {
|