@elisra-devops/docgen-data-provider 1.83.0 → 1.85.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 +5 -0
- package/bin/modules/ResultDataProvider.js +221 -23
- package/bin/modules/ResultDataProvider.js.map +1 -1
- package/bin/tests/modules/ResultDataProvider.test.js +209 -0
- package/bin/tests/modules/ResultDataProvider.test.js.map +1 -1
- package/bin/utils/mewpExternalIngestionUtils.js +9 -0
- package/bin/utils/mewpExternalIngestionUtils.js.map +1 -1
- package/package.json +1 -1
- package/src/modules/ResultDataProvider.ts +250 -19
- package/src/tests/modules/ResultDataProvider.test.ts +254 -0
- package/src/utils/mewpExternalIngestionUtils.ts +11 -0
|
@@ -88,6 +88,7 @@ export default class ResultDataProvider {
|
|
|
88
88
|
private buildMewpCoverageL3L4Rows;
|
|
89
89
|
private buildMewpCoverageRows;
|
|
90
90
|
private resolveCoverageBugResponsibility;
|
|
91
|
+
private buildMewpTestCaseResponsibilityMap;
|
|
91
92
|
private resolveMewpL2RunStatus;
|
|
92
93
|
private fetchMewpScopedTestData;
|
|
93
94
|
private extractRelNumberFromSuite;
|
|
@@ -101,7 +102,10 @@ export default class ResultDataProvider {
|
|
|
101
102
|
private buildMewpTestCaseTitleMap;
|
|
102
103
|
private extractMewpTestCaseId;
|
|
103
104
|
private buildTestCaseStepsXmlMap;
|
|
105
|
+
private extractStepsXmlFromTestCaseItem;
|
|
106
|
+
private extractStepsXmlFromFieldsMap;
|
|
104
107
|
private extractStepsXmlFromWorkItemFields;
|
|
108
|
+
private enrichMewpStepsXmlMapFromWorkItems;
|
|
105
109
|
private classifyRequirementStepOutcome;
|
|
106
110
|
private accumulateRequirementCountsFromActionResults;
|
|
107
111
|
private resolveRequirementStatusForWindow;
|
|
@@ -131,6 +135,7 @@ export default class ResultDataProvider {
|
|
|
131
135
|
private extractLinkedWorkItemIdsFromRelations;
|
|
132
136
|
private extractMewpRequirementIdentifier;
|
|
133
137
|
private deriveMewpResponsibility;
|
|
138
|
+
private deriveMewpTestCaseResponsibility;
|
|
134
139
|
private deriveMewpSubSystem;
|
|
135
140
|
private resolveBugResponsibility;
|
|
136
141
|
private resolveMewpResponsibility;
|
|
@@ -306,6 +306,7 @@ class ResultDataProvider {
|
|
|
306
306
|
const requirements = this.collapseMewpRequirementFamilies(allRequirements, (scopedRequirementKeys === null || scopedRequirementKeys === void 0 ? void 0 : scopedRequirementKeys.size) ? scopedRequirementKeys : undefined);
|
|
307
307
|
const l2ToLinkedL1BaseKeys = await this.buildMewpL2ToLinkedL1BaseKeys(allRequirements, projectName, testData);
|
|
308
308
|
const requirementSapWbsByBaseKey = this.buildRequirementSapWbsByBaseKey(allRequirements);
|
|
309
|
+
const testCaseResponsibilityById = await this.buildMewpTestCaseResponsibilityMap(testData, projectName);
|
|
309
310
|
const externalBugsByTestCase = await this.loadExternalBugsByTestCase(options === null || options === void 0 ? void 0 : options.externalBugsFile);
|
|
310
311
|
const externalL3L4ByBaseKey = await this.loadExternalL3L4ByBaseKey(options === null || options === void 0 ? void 0 : options.externalL3L4File, requirementSapWbsByBaseKey);
|
|
311
312
|
const hasExternalBugsFile = !!String(((_a = options === null || options === void 0 ? void 0 : options.externalBugsFile) === null || _a === void 0 ? void 0 : _a.name) ||
|
|
@@ -442,7 +443,7 @@ class ResultDataProvider {
|
|
|
442
443
|
logger_1.default.warn(`MEWP coverage join diagnostics: no overlap between external bug test cases and failed test cases. ` +
|
|
443
444
|
`Bug rows remain empty because bugs are shown only for failed L2s.`);
|
|
444
445
|
}
|
|
445
|
-
const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2);
|
|
446
|
+
const rows = this.buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, externalL3L4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2, testCaseResponsibilityById);
|
|
446
447
|
const coverageRowStats = rows.reduce((acc, row) => {
|
|
447
448
|
const hasBug = Number((row === null || row === void 0 ? void 0 : row['Bug ID']) || 0) > 0;
|
|
448
449
|
const hasL3 = String((row === null || row === void 0 ? void 0 : row['L3 REQ ID']) || '').trim() !== '';
|
|
@@ -506,6 +507,11 @@ class ResultDataProvider {
|
|
|
506
507
|
allTestCaseIds.add(id);
|
|
507
508
|
}
|
|
508
509
|
}
|
|
510
|
+
const preloadedStepXmlCount = stepsXmlByTestCase.size;
|
|
511
|
+
const fallbackStepLoadStats = await this.enrichMewpStepsXmlMapFromWorkItems(projectName, [...allTestCaseIds], stepsXmlByTestCase);
|
|
512
|
+
logger_1.default.info(`MEWP internal validation steps source summary: testCases=${allTestCaseIds.size} ` +
|
|
513
|
+
`fromSuitePayload=${preloadedStepXmlCount} fromWorkItemFallback=${fallbackStepLoadStats.loadedFromFallback} ` +
|
|
514
|
+
`stepsXmlAvailable=${stepsXmlByTestCase.size} unresolved=${fallbackStepLoadStats.unresolvedCount}`);
|
|
509
515
|
const validL2BaseKeys = new Set([...requirementFamilies.keys()]);
|
|
510
516
|
const diagnostics = {
|
|
511
517
|
totalTestCases: 0,
|
|
@@ -808,7 +814,7 @@ class ResultDataProvider {
|
|
|
808
814
|
return String((a === null || a === void 0 ? void 0 : a.l4Id) || '').localeCompare(String((b === null || b === void 0 ? void 0 : b.l4Id) || ''));
|
|
809
815
|
});
|
|
810
816
|
}
|
|
811
|
-
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2) {
|
|
817
|
+
buildMewpCoverageRows(requirements, requirementIndex, observedTestCaseIdsByRequirement, linkedRequirementsByTestCase, l3l4ByBaseKey, externalBugsByTestCase, externalJoinKeysByL2, testCaseResponsibilityById) {
|
|
812
818
|
var _a;
|
|
813
819
|
const rows = [];
|
|
814
820
|
const linkedByRequirement = this.invertBaseRequirementLinks(linkedRequirementsByTestCase);
|
|
@@ -842,7 +848,7 @@ class ResultDataProvider {
|
|
|
842
848
|
const bugId = Number((bug === null || bug === void 0 ? void 0 : bug.id) || 0);
|
|
843
849
|
if (!Number.isFinite(bugId) || bugId <= 0)
|
|
844
850
|
continue;
|
|
845
|
-
aggregatedBugs.set(bugId, Object.assign(Object.assign({}, bug), { responsibility: this.resolveCoverageBugResponsibility(String((bug === null || bug === void 0 ? void 0 : bug.responsibility) || ''), requirement) }));
|
|
851
|
+
aggregatedBugs.set(bugId, Object.assign(Object.assign({}, bug), { responsibility: this.resolveCoverageBugResponsibility(String((bug === null || bug === void 0 ? void 0 : bug.responsibility) || ''), requirement, String((testCaseResponsibilityById === null || testCaseResponsibilityById === void 0 ? void 0 : testCaseResponsibilityById.get(testCaseId)) || '')) }));
|
|
846
852
|
}
|
|
847
853
|
}
|
|
848
854
|
}
|
|
@@ -869,18 +875,114 @@ class ResultDataProvider {
|
|
|
869
875
|
}
|
|
870
876
|
return rows;
|
|
871
877
|
}
|
|
872
|
-
resolveCoverageBugResponsibility(rawResponsibility, requirement) {
|
|
873
|
-
const
|
|
878
|
+
resolveCoverageBugResponsibility(rawResponsibility, requirement, testCaseResponsibility = '') {
|
|
879
|
+
const normalizeDisplay = (value) => {
|
|
880
|
+
const direct = String(value || '').trim();
|
|
881
|
+
if (!direct)
|
|
882
|
+
return '';
|
|
883
|
+
const resolved = this.resolveMewpResponsibility(this.toMewpComparableText(direct));
|
|
884
|
+
if (resolved === 'ESUK')
|
|
885
|
+
return 'ESUK';
|
|
886
|
+
if (resolved === 'IL')
|
|
887
|
+
return 'Elisra';
|
|
888
|
+
return direct;
|
|
889
|
+
};
|
|
890
|
+
const direct = normalizeDisplay(rawResponsibility);
|
|
874
891
|
if (direct && direct.toLowerCase() !== 'unknown')
|
|
875
892
|
return direct;
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
893
|
+
const fromTestCase = normalizeDisplay(testCaseResponsibility);
|
|
894
|
+
if (fromTestCase && fromTestCase.toLowerCase() !== 'unknown')
|
|
895
|
+
return fromTestCase;
|
|
896
|
+
const fromRequirement = normalizeDisplay(String((requirement === null || requirement === void 0 ? void 0 : requirement.responsibility) || ''));
|
|
897
|
+
if (fromRequirement && fromRequirement.toLowerCase() !== 'unknown')
|
|
898
|
+
return fromRequirement;
|
|
899
|
+
return direct || fromTestCase || fromRequirement || 'Unknown';
|
|
900
|
+
}
|
|
901
|
+
async buildMewpTestCaseResponsibilityMap(testData, projectName) {
|
|
902
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
903
|
+
const out = new Map();
|
|
904
|
+
const unresolved = new Set();
|
|
905
|
+
const extractFromWorkItemFields = (workItemFields) => {
|
|
906
|
+
const fields = {};
|
|
907
|
+
if (!Array.isArray(workItemFields))
|
|
908
|
+
return fields;
|
|
909
|
+
for (const field of workItemFields) {
|
|
910
|
+
const keyCandidates = [field === null || field === void 0 ? void 0 : field.key, field === null || field === void 0 ? void 0 : field.name, field === null || field === void 0 ? void 0 : field.referenceName]
|
|
911
|
+
.map((item) => String(item || '').trim())
|
|
912
|
+
.filter((item) => !!item);
|
|
913
|
+
for (const key of keyCandidates) {
|
|
914
|
+
fields[key] = field === null || field === void 0 ? void 0 : field.value;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
return fields;
|
|
918
|
+
};
|
|
919
|
+
for (const suite of testData || []) {
|
|
920
|
+
const testCasesItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testCasesItems) ? suite.testCasesItems : [];
|
|
921
|
+
for (const testCase of testCasesItems) {
|
|
922
|
+
const testCaseId = Number(((_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCase === null || testCase === void 0 ? void 0 : testCase.testCaseId) || (testCase === null || testCase === void 0 ? void 0 : testCase.id) || 0);
|
|
923
|
+
if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
|
|
924
|
+
continue;
|
|
925
|
+
const workItemFieldsMap = ((_b = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _b === void 0 ? void 0 : _b.fields) || {};
|
|
926
|
+
const workItemFieldsList = extractFromWorkItemFields((_c = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _c === void 0 ? void 0 : _c.workItemFields);
|
|
927
|
+
const directFieldAliases = Object.fromEntries(Object.entries({
|
|
928
|
+
'System.AreaPath': ((_d = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _d === void 0 ? void 0 : _d.areaPath) ||
|
|
929
|
+
((_e = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _e === void 0 ? void 0 : _e.AreaPath) ||
|
|
930
|
+
(testCase === null || testCase === void 0 ? void 0 : testCase.areaPath) ||
|
|
931
|
+
(testCase === null || testCase === void 0 ? void 0 : testCase.AreaPath) ||
|
|
932
|
+
((_f = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _f === void 0 ? void 0 : _f.areaPath) ||
|
|
933
|
+
((_g = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _g === void 0 ? void 0 : _g.AreaPath),
|
|
934
|
+
'Area Path': ((_h = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _h === void 0 ? void 0 : _h['Area Path']) ||
|
|
935
|
+
(testCase === null || testCase === void 0 ? void 0 : testCase['Area Path']) ||
|
|
936
|
+
((_j = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _j === void 0 ? void 0 : _j['Area Path']),
|
|
937
|
+
AreaPath: ((_k = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _k === void 0 ? void 0 : _k.AreaPath) ||
|
|
938
|
+
(testCase === null || testCase === void 0 ? void 0 : testCase.AreaPath) ||
|
|
939
|
+
((_l = testCase === null || testCase === void 0 ? void 0 : testCase.testCase) === null || _l === void 0 ? void 0 : _l.AreaPath),
|
|
940
|
+
}).filter(([, value]) => value !== undefined && value !== null && String(value).trim() !== ''));
|
|
941
|
+
const fromWorkItem = this.deriveMewpTestCaseResponsibility(Object.assign(Object.assign(Object.assign({}, directFieldAliases), workItemFieldsList), workItemFieldsMap));
|
|
942
|
+
if (fromWorkItem) {
|
|
943
|
+
out.set(testCaseId, fromWorkItem);
|
|
944
|
+
}
|
|
945
|
+
else {
|
|
946
|
+
unresolved.add(testCaseId);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
const testPointsItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testPointsItems) ? suite.testPointsItems : [];
|
|
950
|
+
for (const testPoint of testPointsItems) {
|
|
951
|
+
const testCaseId = Number((testPoint === null || testPoint === void 0 ? void 0 : testPoint.testCaseId) || ((_m = testPoint === null || testPoint === void 0 ? void 0 : testPoint.testCase) === null || _m === void 0 ? void 0 : _m.id) || 0);
|
|
952
|
+
if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
|
|
953
|
+
continue;
|
|
954
|
+
const fromPoint = this.deriveMewpTestCaseResponsibility({
|
|
955
|
+
'System.AreaPath': (testPoint === null || testPoint === void 0 ? void 0 : testPoint.areaPath) || (testPoint === null || testPoint === void 0 ? void 0 : testPoint.AreaPath),
|
|
956
|
+
'Area Path': testPoint === null || testPoint === void 0 ? void 0 : testPoint['Area Path'],
|
|
957
|
+
AreaPath: testPoint === null || testPoint === void 0 ? void 0 : testPoint.AreaPath,
|
|
958
|
+
});
|
|
959
|
+
if (fromPoint) {
|
|
960
|
+
out.set(testCaseId, fromPoint);
|
|
961
|
+
unresolved.delete(testCaseId);
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
unresolved.add(testCaseId);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (unresolved.size > 0) {
|
|
969
|
+
try {
|
|
970
|
+
const workItems = await this.fetchWorkItemsByIds(projectName, [...unresolved], false);
|
|
971
|
+
for (const workItem of workItems || []) {
|
|
972
|
+
const testCaseId = Number((workItem === null || workItem === void 0 ? void 0 : workItem.id) || 0);
|
|
973
|
+
if (!Number.isFinite(testCaseId) || testCaseId <= 0 || out.has(testCaseId))
|
|
974
|
+
continue;
|
|
975
|
+
const resolved = this.deriveMewpTestCaseResponsibility((workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {});
|
|
976
|
+
if (!resolved)
|
|
977
|
+
continue;
|
|
978
|
+
out.set(testCaseId, resolved);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
catch (error) {
|
|
982
|
+
logger_1.default.warn(`MEWP coverage: failed to enrich test-case responsibility fallback: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return out;
|
|
884
986
|
}
|
|
885
987
|
resolveMewpL2RunStatus(input) {
|
|
886
988
|
if (((input === null || input === void 0 ? void 0 : input.failed) || 0) > 0)
|
|
@@ -1141,18 +1243,17 @@ class ResultDataProvider {
|
|
|
1141
1243
|
return Number.isFinite(testCaseId) ? testCaseId : 0;
|
|
1142
1244
|
}
|
|
1143
1245
|
buildTestCaseStepsXmlMap(testData) {
|
|
1144
|
-
var _a
|
|
1246
|
+
var _a;
|
|
1145
1247
|
const map = new Map();
|
|
1146
1248
|
for (const suite of testData || []) {
|
|
1147
1249
|
const testCasesItems = Array.isArray(suite === null || suite === void 0 ? void 0 : suite.testCasesItems) ? suite.testCasesItems : [];
|
|
1148
1250
|
for (const testCase of testCasesItems) {
|
|
1149
|
-
const id = Number((_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.id);
|
|
1251
|
+
const id = Number(((_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.id) || (testCase === null || testCase === void 0 ? void 0 : testCase.testCaseId) || (testCase === null || testCase === void 0 ? void 0 : testCase.id) || 0);
|
|
1150
1252
|
if (!Number.isFinite(id))
|
|
1151
1253
|
continue;
|
|
1152
1254
|
if (map.has(id))
|
|
1153
1255
|
continue;
|
|
1154
|
-
const
|
|
1155
|
-
const stepsXml = this.extractStepsXmlFromWorkItemFields(fields);
|
|
1256
|
+
const stepsXml = this.extractStepsXmlFromTestCaseItem(testCase);
|
|
1156
1257
|
if (stepsXml) {
|
|
1157
1258
|
map.set(id, stepsXml);
|
|
1158
1259
|
}
|
|
@@ -1160,6 +1261,43 @@ class ResultDataProvider {
|
|
|
1160
1261
|
}
|
|
1161
1262
|
return map;
|
|
1162
1263
|
}
|
|
1264
|
+
extractStepsXmlFromTestCaseItem(testCase) {
|
|
1265
|
+
var _a, _b, _c, _d, _e;
|
|
1266
|
+
const fieldsList = (_a = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _a === void 0 ? void 0 : _a.workItemFields;
|
|
1267
|
+
const fromFieldList = this.extractStepsXmlFromWorkItemFields(fieldsList);
|
|
1268
|
+
if (fromFieldList)
|
|
1269
|
+
return fromFieldList;
|
|
1270
|
+
const workItemFields = ((_b = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _b === void 0 ? void 0 : _b.fields) || {};
|
|
1271
|
+
const fromFieldsMap = this.extractStepsXmlFromFieldsMap(workItemFields);
|
|
1272
|
+
if (fromFieldsMap)
|
|
1273
|
+
return fromFieldsMap;
|
|
1274
|
+
const directCandidates = [
|
|
1275
|
+
testCase === null || testCase === void 0 ? void 0 : testCase.stepsResultXml,
|
|
1276
|
+
(_c = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _c === void 0 ? void 0 : _c.stepsResultXml,
|
|
1277
|
+
(_d = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _d === void 0 ? void 0 : _d['Microsoft.VSTS.TCM.Steps'],
|
|
1278
|
+
(_e = testCase === null || testCase === void 0 ? void 0 : testCase.workItem) === null || _e === void 0 ? void 0 : _e.steps,
|
|
1279
|
+
];
|
|
1280
|
+
for (const candidate of directCandidates) {
|
|
1281
|
+
const value = String(candidate || '').trim();
|
|
1282
|
+
if (value)
|
|
1283
|
+
return value;
|
|
1284
|
+
}
|
|
1285
|
+
return '';
|
|
1286
|
+
}
|
|
1287
|
+
extractStepsXmlFromFieldsMap(fields) {
|
|
1288
|
+
const directCandidates = [
|
|
1289
|
+
fields === null || fields === void 0 ? void 0 : fields['Microsoft.VSTS.TCM.Steps'],
|
|
1290
|
+
fields === null || fields === void 0 ? void 0 : fields['microsoft.vsts.tcm.steps'],
|
|
1291
|
+
fields === null || fields === void 0 ? void 0 : fields['Steps'],
|
|
1292
|
+
fields === null || fields === void 0 ? void 0 : fields['steps'],
|
|
1293
|
+
];
|
|
1294
|
+
for (const candidate of directCandidates) {
|
|
1295
|
+
const value = String(candidate || '').trim();
|
|
1296
|
+
if (value)
|
|
1297
|
+
return value;
|
|
1298
|
+
}
|
|
1299
|
+
return '';
|
|
1300
|
+
}
|
|
1163
1301
|
extractStepsXmlFromWorkItemFields(workItemFields) {
|
|
1164
1302
|
if (!Array.isArray(workItemFields))
|
|
1165
1303
|
return '';
|
|
@@ -1178,6 +1316,36 @@ class ResultDataProvider {
|
|
|
1178
1316
|
}
|
|
1179
1317
|
return '';
|
|
1180
1318
|
}
|
|
1319
|
+
async enrichMewpStepsXmlMapFromWorkItems(projectName, testCaseIds, stepsXmlByTestCase) {
|
|
1320
|
+
const missingIds = [...new Set(testCaseIds)]
|
|
1321
|
+
.map((id) => Number(id))
|
|
1322
|
+
.filter((id) => Number.isFinite(id) && id > 0)
|
|
1323
|
+
.filter((id) => !stepsXmlByTestCase.has(id));
|
|
1324
|
+
if (missingIds.length === 0) {
|
|
1325
|
+
return { loadedFromFallback: 0, unresolvedCount: 0 };
|
|
1326
|
+
}
|
|
1327
|
+
let loadedFromFallback = 0;
|
|
1328
|
+
try {
|
|
1329
|
+
const workItems = await this.fetchWorkItemsByIds(projectName, missingIds, false);
|
|
1330
|
+
for (const workItem of workItems || []) {
|
|
1331
|
+
const id = Number((workItem === null || workItem === void 0 ? void 0 : workItem.id) || 0);
|
|
1332
|
+
if (!Number.isFinite(id) || id <= 0 || stepsXmlByTestCase.has(id))
|
|
1333
|
+
continue;
|
|
1334
|
+
const stepsXml = this.extractStepsXmlFromFieldsMap((workItem === null || workItem === void 0 ? void 0 : workItem.fields) || {});
|
|
1335
|
+
if (!stepsXml)
|
|
1336
|
+
continue;
|
|
1337
|
+
stepsXmlByTestCase.set(id, stepsXml);
|
|
1338
|
+
loadedFromFallback += 1;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
catch (error) {
|
|
1342
|
+
logger_1.default.warn(`MEWP internal validation: failed loading missing steps via work-item fallback: ${(error === null || error === void 0 ? void 0 : error.message) || error}`);
|
|
1343
|
+
}
|
|
1344
|
+
return {
|
|
1345
|
+
loadedFromFallback,
|
|
1346
|
+
unresolvedCount: Math.max(0, missingIds.length - loadedFromFallback),
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1181
1349
|
classifyRequirementStepOutcome(outcome) {
|
|
1182
1350
|
const normalized = String(outcome || '')
|
|
1183
1351
|
.trim()
|
|
@@ -1927,11 +2095,42 @@ class ResultDataProvider {
|
|
|
1927
2095
|
return fromExplicitLabel;
|
|
1928
2096
|
if (explicitSapWbsByLabel)
|
|
1929
2097
|
return explicitSapWbsByLabel;
|
|
1930
|
-
const
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
2098
|
+
const areaPathCandidates = [
|
|
2099
|
+
fields === null || fields === void 0 ? void 0 : fields['System.AreaPath'],
|
|
2100
|
+
fields === null || fields === void 0 ? void 0 : fields['Area Path'],
|
|
2101
|
+
fields === null || fields === void 0 ? void 0 : fields['AreaPath'],
|
|
2102
|
+
];
|
|
2103
|
+
for (const candidate of areaPathCandidates) {
|
|
2104
|
+
const normalized = this.toMewpComparableText(candidate);
|
|
2105
|
+
const resolved = this.resolveMewpResponsibility(normalized);
|
|
2106
|
+
if (resolved)
|
|
2107
|
+
return resolved;
|
|
2108
|
+
}
|
|
2109
|
+
const keyHints = ['sapwbs', 'responsibility', 'owner', 'areapath', 'area path'];
|
|
2110
|
+
for (const [key, value] of Object.entries(fields || {})) {
|
|
2111
|
+
const normalizedKey = String(key || '').toLowerCase();
|
|
2112
|
+
if (!keyHints.some((hint) => normalizedKey.includes(hint)))
|
|
2113
|
+
continue;
|
|
2114
|
+
const resolved = this.resolveMewpResponsibility(this.toMewpComparableText(value));
|
|
2115
|
+
if (resolved)
|
|
2116
|
+
return resolved;
|
|
2117
|
+
}
|
|
2118
|
+
return '';
|
|
2119
|
+
}
|
|
2120
|
+
// Test-case responsibility must come from test-case path context (not SAPWBS).
|
|
2121
|
+
deriveMewpTestCaseResponsibility(fields) {
|
|
2122
|
+
const areaPathCandidates = [
|
|
2123
|
+
fields === null || fields === void 0 ? void 0 : fields['System.AreaPath'],
|
|
2124
|
+
fields === null || fields === void 0 ? void 0 : fields['Area Path'],
|
|
2125
|
+
fields === null || fields === void 0 ? void 0 : fields['AreaPath'],
|
|
2126
|
+
];
|
|
2127
|
+
for (const candidate of areaPathCandidates) {
|
|
2128
|
+
const normalized = this.toMewpComparableText(candidate);
|
|
2129
|
+
const resolved = this.resolveMewpResponsibility(normalized);
|
|
2130
|
+
if (resolved)
|
|
2131
|
+
return resolved;
|
|
2132
|
+
}
|
|
2133
|
+
const keyHints = ['areapath', 'area path', 'responsibility', 'owner'];
|
|
1935
2134
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
1936
2135
|
const normalizedKey = String(key || '').toLowerCase();
|
|
1937
2136
|
if (!keyHints.some((hint) => normalizedKey.includes(hint)))
|
|
@@ -2333,7 +2532,6 @@ class ResultDataProvider {
|
|
|
2333
2532
|
logger_1.default.warn(`Invalid run result ${runId} or result ${resultId}`);
|
|
2334
2533
|
return null;
|
|
2335
2534
|
}
|
|
2336
|
-
logger_1.default.warn(`Current Test point for Test case ${point.testCaseId} is in Active state`);
|
|
2337
2535
|
const url = `${this.orgUrl}${projectName}/_apis/wit/workItems/${point.testCaseId}?$expand=all`;
|
|
2338
2536
|
const testCaseData = await tfs_1.TFSServices.getItemContent(url, this.token);
|
|
2339
2537
|
const newResultData = {
|